正則表達式簡明教程

 

本文目錄

1、正則表達式用途java

2、資料與工具正則表達式

3、正則基礎知識編程

4、正則進階知識windows

5、在Java中使用正則編程語言

6、Java正則中遇到的問題工具

1、正則表達式用途

正則表達式是一個有含義的字符串,它表明了一個字符串的組成規則,用於驗證給定字符串是否與我匹配。比方說,當你要求用戶填寫郵箱時,你就須要用正則表達式來驗證用戶輸入的是否是有效的郵箱地址。post

2、資料與工具

網上的學習資料不少,可是濫竽充數的也很多。個人學習資料是《正則表達式30分鐘入門教程》,本文至關因而在該文章的基礎上提煉而成的。在學習過程當中你不須要經過編程來驗證,那樣太慢,能夠在正則驗證工具-chinaZ驗證你的正則表達式。學習

3、正則基礎知識

若是你寫過批處理或者善於使用windows系統的搜索功能,那麼你必定對通配符不陌生。在windows中,*表明任意數量的字符。不要擔憂,正則表達式沒有那麼可怕,它與這個通配符是相似的。測試

3.1 內容匹配

咱們把正則中具備特定含義的字符成爲元字符,那麼最基本的元字符有2種:(1)匹配字符內容(2)匹配字符數量。經常使用的內容匹配元字符見表1網站

1.經常使用的內容匹配元字符

代碼

說明

.

匹配除換行符之外的任意字符

\w

匹配字母或數字或下劃線或漢字

\s

匹配任意的空白符

\d

匹配數字

\b

匹配單詞的開始或結束

^

匹配字符串的開始

$

匹配字符串的結束

注意,沒跟數量匹配元字符時,它們都只能匹配1個字符。從表1能夠看到,」.」幾乎可以匹配任何字符;若是你要匹配一個字母或者數字,使用\w就能夠了;匹配數字可使用\d

下面是幾個例子(正則表達式位於」」內):

「\bre\w\b」的含義是:匹配一個單詞,以re打頭後面再跟一個字符。注意,正則表達式裏面說的單詞不等於英文單詞,這裏的單詞能夠包含數字或字符。以」re1d rere1 re_」爲例,本正則不能匹配前兩個單詞,只能匹配後兩個單詞。

「^\d[135][a-f]$」的含義是:匹配一個字符串,且第一個字符是數字,第二個字符是1或者3或者5,第三個字符是a-f之間的字符。也就是說,[]能夠定義字符的範圍,裏面的橫線表示範圍,如無橫線則各字符爲或的關係。」15c」能夠匹配,」15g」不能匹配。

3.2 數量匹配

假設我要匹配一個長達1000位的字符串,我總不可能構造一個1000位的正則吧!固然,數量匹配元字符可以定義指定字符的數量。經常使用的數量匹配元字符見表2

2 經常使用的數量匹配元字符

代碼/語法

說明

*

重複零次或更屢次

+

重複一次或更屢次

?

重複零次或一次

{n}

重複n

{n,}

重複n次或更屢次

{n,m}

重複nm

結合表1,當你使用.*的時候基本就能表示任意內容了。下面仍然經過例子來進行解釋:

「^0\d{2,3}-\d{7,8}$」的含義是:匹配一個字符串,且第一個字符是0,後面跟2位到3位數字,再跟1個橫線,再跟7-8位數字。沒錯,這就是驗證座機號碼的正則。」010-77777779」可以匹配,而」010-7777777a」不能匹配。

「^\w+\@\w+\.\w{2,}$」的含義是:匹配一個字符串,首先是一位或多位字符,接下來是」@」符號,接下來是一位或多位字符,而後是」.」,最後是2位或多位字符。」111@163.com」能夠匹配,」111@.com」不能匹配。

"^[1-9]\d{16}(\d|x|X)$"的含義是:匹配一個字符串,且第一位部位0,接下來是16位數字,最後一位是數字或大小寫」x」。沒錯,這是驗證18位身份證號的正則。注意,」|」表示邏輯或。」01066119880124001x」不能匹配,」41066119880124001x」能夠匹配。

3.3 轉義取反與分枝

若是你就想匹配元字符自己,使用轉移字符就行了,這與編程語言是同樣的。好比,」\\」匹配」\」,「\?」 匹配「?」。須要注意的是,在程序中制定正則字符串時,你須要使用不少轉義。好比你的實際正則爲「^0\d{2,3}-\d{7,8}$」,那你在程序中應寫爲「^0\\d{2,3}-\\d{7,8}$」,由於在編程語言層面就會對字符串中的轉義字符過濾一遍。

[^xyz]表示取反,即不匹配xyz。與元字符對應,也有一系列取反代碼,具體見表3

3 經常使用的取反匹配元字符

代碼/語法

說明

\W

匹配任意不是字母,數字,下劃線,漢字的字符

\S

匹配任意不是空白符的字符

\D

匹配任意非數字的字符

\B

匹配不是單詞開頭或結束的位置

[^x]

匹配除了x之外的任意字符

[^aeiou]

匹配除了aeiou這幾個字母之外的任意字符

 

分枝條件就是邏輯或。好比,」\(0\d{2}\)-\d{8}|0\d{2}-\d{8}」匹配的內容爲,3位區號-8位號碼,其中區號爲帶括號或者不帶括號。

4、正則進階知識

4.1 分組與向後引用

咱們經常用括號來包圍一些子表達式,好比說,」(\d{1,3}\.){3}(\d{1,3})」用於匹配一個IP地址(不嚴謹匹配)。括號之內的範圍就是一個分組。正則工做時會給每一個分組編號,並記錄分組所匹配的內容。簡單來講,從左往右,以左括號爲標誌,第一個分組編號爲1,第二個爲2,以此類推,正則表達式自身編號爲0。除此之外,正則容許你自定義分組名稱,或者指定某分組不編號,具體以下:

4.經常使用分組語法

序號

分類

代碼/語法

說明

1

捕獲

(exp)

匹配exp,並捕獲文本到自動命名的組裏

2

(?<name>exp)

匹配exp,並捕獲文本到名稱爲name的組裏,也能夠寫成(?'name'exp)

 

3

(?:exp)

匹配exp,不捕獲匹配的文本,也不給此分組分配組號

 

4

零寬斷言

(?=exp)

匹配exp前面的位置

5

(?<=exp)

匹配exp後面的位置

 

6

(?!exp)

匹配後面跟的不是exp的位置

 

7

(?<!exp)

匹配前面不是exp的位置

 

8

註釋

(?#comment)

這種類型的分組不對正則表達式的處理產生任何影響,用於提供註釋讓人閱讀

 

由表可見,前三項都在解釋組號命名的問題。那麼組號有什麼用呢?

  1. 組號可以被正則的其它部分引用,以再次匹配某個組,這樣你就不用在正則中寫不少重複的子表達式。好比說,」\b(\w+)\b\s+\1\b」用於匹配2個單詞,第一個由若干字母組成,第二個引用第一個分組,即與第一個單詞相同。它匹配」ha ha」。
  2. Java語言爲例,使用matchergroup(i)方法可以輸出每個分組所匹配的內容。其中i是組號。

下面是幾個示例。

1."^(\d{1,3}\.){3}(\d{1,3})$"的含義是:匹配一個字符串,形式如xx.xx.xx.xx,其中xx13位整數。」222.213.24.57」匹配。各分組匹配內容爲:

group 0 : 222.213.24.57

group 1 : 24.

group 2 : 57

由於正則中包含2對括號,所以不算自身只有2個分組。因爲分組1重複匹配3次,所以它只能記錄第三次匹配的內容也就是」24.」。分組2記錄的匹配內容是」57」。

2."^(\\d{1,3})\\.\\1\\.\\1\\.\\1$"的含義爲,匹配一個字符串,形式如xx.xx.xx.xx,其中xx13位整數,全部的xx都相同。它與」222.213.24.57」不匹配,與」222.222.222.222」匹配。

3."^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$"的含義與例1相同,只不過將每一個分組單獨寫了出來。各分組匹配內容以下,再也不解釋。

group 0 : 222.213.24.57

group 1 : 222

group 2 : 213

group 3 : 24

group 4 : 57

4."(?:\\d{1,3})\\.(\\d{1,3})\\.(?:\\d{1,3})\\.(\\d{1,3})"的含義與例1相同,仍然會與」222.213.24.57」匹配。區別在於分組1和分組3不分配組號且不記錄匹配內容,各分組及匹配內容以下:

group 0 : 222.213.24.57

group 1 : 213

group 2 : 57

4.2 零寬斷言

簡單來講,零寬斷言表明如下的規則:指定字符串以xxx打頭、以xxx結尾、不以xxx打頭或不以xxx結尾。並匹配除了xxx之外的內容。零寬指的是規則發生的位置,它沒有寬度,不做爲字符處理。

(?=exp)也叫零寬度正預測先行斷言,它斷言自身出現的位置的後面能匹配表達式exp。好比\b\w+(?=ing\b),匹配以ing結尾的單詞的前面部分(除了ing之外的部分),如查找I'm singing while you're dancing.時,它會匹配singdanc

(?<=exp)也叫零寬度正回顧後發斷言,它斷言自身出現的位置的前面能匹配表達式exp。好比(?<=\bre)\w+\b會匹配以re開頭的單詞的後半部分(除了re之外的部分),例如在查找reading a book時,它匹配ading

(?!exp)也叫作零寬度負預測先行斷言,斷言此位置的後面不能匹配表達式exp。例如:\d{3}(?!\d)匹配三位數字,並且這三位數字的後面不能是數字;\b((?!abc)\w)+\b匹配不包含連續字符串abc的單詞。

(?<!exp)也叫作零寬度負回顧後發斷言來斷言此位置的前面不能匹配表達式exp。例如,(?<![a-z])\d{7}匹配前面不是小寫字母的七位數字。

4.3 貪婪與懶惰

正則的匹配默認是貪婪的,也就是說若是條件容許它將匹配儘量多的字符。好比,」a.*b」將匹配」aabab」的所有,而不是」aab」或」ab」。然而有時咱們也須要最小匹配,只須要在正則後面加一個」?」便可。好比說,a.*?b匹配最短的,以a開始,以b結束的字符串。若是把它應用於aabab的話,它會匹配aab(第一到第三個字符)和ab(第四到第五個字符)。

5.懶惰限定符

代碼/語法

說明

*?

重複任意次,但儘量少重複

+?

重複1次或更屢次,但儘量少重複

??

重複0次或1次,但儘量少重複

{n,m}?

重複nm次,但儘量少重複

{n,}?

重複n次以上,但儘量少重複

 

5、在Java中使用正則

5.1基本代碼格式

Java中使用正則時,須要2個基本要素:Pattern和Matcher。前者是你定義的正則,後者是由該正則生成的匹配器。代碼格式以下:

public  boolean startCheck(String reg,String string)  

    {  

        boolean tem=false;          

        Pattern pattern = Pattern.compile(reg);  

        Matcher matcher = pattern.matcher(string);             

        tem = matcher.matches();

        return tem;  

    }

 

5.2驗證手機號

/** 
         * 手機號碼驗證,11位,開頭必須是1,總長11位數 
         * */  
        public boolean checkCellPhone(String cellPhoneNr)  
        {  
            String reg="^[1][\\d]{10}$";  
            return startCheck(reg,cellPhoneNr);  
        } 

 

5.3驗證電子郵箱

/** 
         * 檢查EMAIL地址 ,用戶名和網站名稱必須>=1位字符 
         * 地址結尾必須是2位以上,如:cn,test,com,info 
         * */  
        public boolean checkEmail(String email)  
        {  
            String regex="\\w+\\@\\w+\\.\\w{2,}";  
              
            return startCheck(regex,email);  
        } 

 

5.4驗證身份證號

/** 
         * 驗證國內身份證號碼:18位,由數字組成,不能以0開頭,x或X結尾 
         * */  
        public boolean checkIdCard(String idNr)  
        {  
            String reg="^[1-9]\\d{16}(\\d|x|X)$"; 
            return startCheck(reg,idNr);  
        }  

 

5.5驗證IP

/** 
         *  查看IP地址是否合法 ,0-255 = 250-255, 200-249, 100-199,10-99, 0-9,
         * */  
        public boolean checkIP(String ipAddress)  
        {  
            String subregex = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
            String regex = "(" + subregex + "\\.)"+ "{3}" + subregex;            
            return startCheck(regex,ipAddress);  
        }  

 

5.6驗證郵編

/** 
         * 檢查郵政編碼(中國),6位,第一位必須是非0開頭,其餘5位數字爲0-9 
         * */  
        public boolean checkPostcode(String postCode)  
        {  
            String regex="^[1-9]\\d{5}";  
            return startCheck(regex,postCode);  
        }  

 

5.7驗證用戶名

/** 
         * 檢驗用戶名 
         * 取值範圍爲a-z,A-Z,0-9,"_",漢字,不能以"_"結尾 
         * 用戶名有最小長度和最大長度限制,好比用戶名必須是4-20位 
         * */  
        public boolean checkUsername(String username,int min,int max)  
        {  
            String regex="[\\w_\\-\u4e00-\u9fa5]{"+min+","+max+"}(?<!_)";
            return startCheck(regex,username);  
        }  

 

5.8驗證網址

/** 
         * 網址驗證<br> 
         * 符合類型:<br> 
         *  url=協議類型://  0或1次
         *  www.  0或1次
         *  xx.xx   xx爲數字字符不限長度
         * */  
        public boolean checkWebSite(String url)  
        {  
            //http://www.163.com  
            String reg="^((http|https|ftp)\\:\\/\\/)?(www.)?\\w+\\.\\w+";  
            //String reg="^(http)\\://(\\w+\\.\\w+\\.\\w+|\\w+\\.\\w+)";  
              
            return startCheck(reg,url);  
        }  
        

 

 

6、Java正則中遇到的問題

本章記錄了我在Java中遇到的坑,按需更新。

6.1 測試經過然而matches()返回false

筆者在測試"\\w*(?=ing)"和"Im singing while youre dancing"時,遇到的狀況爲,測試網站顯示可以匹配到singdanc,然而程序中的matches()老是返回false。經點撥才發現,matches()方法老是匹配整個字符串,僅當徹底匹配時纔會返回true。在這種狀況下應當使用find()方法,每當成功匹配到子字符串時,它就會返回true

6.2 Start()end()值異常

代碼以下:

import java.util.regex.Matcher;import java.util.regex.Pattern;

public class RegexDemo {

  public static void main(String[] args) {

    RegexDemo demo = new RegexDemo();

    System.out.printf("%b%n", demo.zeroWidthAssertionEarly());

  }

 

  public boolean zeroWidthAssertionEarly()  

  {  

    //匹配以ing結尾的單詞

    String reg="\\w*(?=ing)";

    String word = "I’m singing while you’re dancing";//

    boolean tem=false;  

 

    Pattern pattern = Pattern.compile(reg);  

    Matcher matcher = pattern.matcher(word);  

 

    while(matcher.find()){

      System.out.printf("start = %d%n", matcher.start());

      System.out.printf("end = %d%n", matcher.end());

    }        

    return tem;  

  } }

 

輸出以下:

start = 4

end = 8

start = 8

end = 8

start = 25

end = 29

start = 29

end = 29false

輸出爲何不是這樣呢?

start = 4

end = 8

start = 25

end = 29false

緣由在於,"\w*"將匹配0或多個字符,所以」ing」將本身匹配本身一次。改成"\w+"後輸出就正常了。

相關文章
相關標籤/搜索