正則表達(dá)式

茫茫人海中,只找到了你

1. 什么是正則表達(dá)式

在某些情況下,我們總是要在某個文本中查找某些復(fù)雜規(guī)則的字符串,正則表達(dá)式就是用戶描述這些規(guī)則的工具(正則表達(dá)式就是記錄文本規(guī)則的代碼)。

2. 舉個簡單的栗子

假設(shè)在一篇英文文章中,你要查找hi這個單詞,這時候查找到的不僅有hi這個單詞,還有類似于hidden、hight等等的,其實這不是我們想要的,我們要的僅僅就是hi這個詞,而這個時候,我們就應(yīng)該使用\bhi\b

  1. 元字符\b:是正則表達(dá)式規(guī)定的一個特殊代碼,代表著單詞的開頭或結(jié)尾,即單詞的分界處。需要說明的是,\b并不匹配單詞分割字符(空格、標(biāo)點符號、換行等),它只匹配一個位置。

  2. 元字符.:用于匹配除了換行符以外的任意字符。

  3. 元字符**既不代表字符,也不是位置,而是數(shù)量;它指定前邊的內(nèi)容可以連續(xù)重復(fù)使用任意次以使得整個表達(dá)式得到匹配。

回到上面的例子,如果更換需求,現(xiàn)在需要查找的是hi###Max,###代表的是任意字符,這時候我們就可以使用上面的三個元字符組合來查找這個特定規(guī)則的字符串了,即: \bhi\b.*\bMax\b。

目前我們只知道三個元字符,如果我們知道了更多的元字符,我們就可以構(gòu)造出更強(qiáng)大的正則表達(dá)式。

1. 元字符

從以上的例子中我們已經(jīng)知道了三個元字符了,下面我就來給大家再通過栗子介紹幾個常用的元字符。

代碼 說明
\w 匹配字母或者數(shù)字或者下劃線或者漢字
\s 匹配任意的空白符(包括空格、制表符、換行符、中文全角空格等)
\d 匹配數(shù)字
\b 匹配單詞的開始或者結(jié)束
^ 匹配字符串的開始
$ 匹配字符串的結(jié)束
  • \ba\w*\b:匹配以字母a開頭的單詞(顯示以單詞開始處\b,然后是字母a,然后是任意數(shù)量的字母或者數(shù)字\w,最后是單詞結(jié)尾處\b)

  • \d+:匹配1個或者更多連續(xù)的數(shù)字。這里的+是和*類似的元字符,不同的是*匹配重復(fù)任意次(可能是0次),而+則匹配重復(fù)1次或者更多次。

  • 0\d{2}-\d{8}:匹配以0開頭,然后是兩個數(shù)字,然后是一個連字號-,最后是8個數(shù)字

  • \b\w{6}\b:匹配剛好6個字符的單詞

  • ^\d{5,12}$:匹配的是5位到12位數(shù)字(因為使用了^$,所以輸入的整個字符串都要用來和\d{5,12}來匹配,即整個輸入的必須是5到12個數(shù)字)

2. 字符轉(zhuǎn)義

如果我想在文本中查找元字符本身的話,該怎么查找呢?這時候就要使用轉(zhuǎn)義了

例如你要查找.,就應(yīng)該使用\.。如果你要查找*,就應(yīng)該使用\*。如果你要查找\,就應(yīng)該使用\\

3. 重復(fù)
代碼 說明
* 重復(fù)零次或者更多次
+ 重復(fù)一次或者更多次
? 重復(fù)零次或者一次
{n} 重復(fù)n次
{n,} 重復(fù)n次或者更多次
{n,m} 重復(fù)n到m次
4. 字符類

\d:代表的是0-9的數(shù)字集合,怎么可以自定義字符集呢,可以使用[]來實現(xiàn)

  • [0-9]代表的意義與\d就是完全一樣的

  • [a-z0-9A-Z]也完全等同于\w(不考慮漢字)

  • \(?0\d{2}[) -]?\d{8}:這個就稍微復(fù)雜了,這個表達(dá)式可以匹配下面幾種格式的電話號碼,如:(010)66668888、022-1133557703312378956 分析一下:首先是一個轉(zhuǎn)義字符\(,后面跟了一個?,代表這個(可以出現(xiàn)一次或者零次,其次是0,后面跟著2位數(shù)字\d{2},再后面是一個字符集分別是)、-,后面有個?,代表這個字符集中的字符可以出現(xiàn)零次或者一次,再之后就是8位數(shù)字咯\d{8}。

5. 分枝條件

正則表達(dá)式里的分枝條件是指有幾種規(guī)則,如果滿足其中任意一種規(guī)則都應(yīng)該匹配,具體方法是使用|把不同的規(guī)則分隔開(分枝條件會從左到右測試執(zhí)行每個條件)。

??

  • 0\d{2}-\d{8}|0\d{3}-\d{7}:這個表達(dá)式能夠匹配到兩種以連字符號分隔的電話號碼:一種是三位區(qū)號、8位本地號碼(如:101-88886666),一種是4位區(qū)號、7位本地號碼(如:0371-6677889)

  • \(0\d{2}\)[- ]?\d{8}|0\d{2}[- ]?\d{8}:這個表達(dá)式匹配3位區(qū)號的電話號碼,其中區(qū)號可以用小括號括起來,也可以不用,區(qū)號與本地號之間可以用連字號或者空格間隔,也可以沒有間隔。

6. 分組

分組的主要目的就是重復(fù)。上面我們已經(jīng)知道了怎么重復(fù)單個字符(直接在字符后面加上限定字符就可以了);但如果想要重復(fù)多個字符改怎么辦呢? 這就用到了分組:使用小括號來指定子表達(dá)式然后就可以指定這個子表達(dá)式的重復(fù)次數(shù)了。

  • ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?):這個表達(dá)式匹配的是IP地址。下面就拆分開來逐個分析咯
    從左到右
  1. 2[0-4]\d:此表達(dá)式主要是匹配200-249的數(shù)字

  2. 25[0-5]:此表達(dá)式主要是匹配250-255的數(shù)字

  3. [01]?\d\d?: 此表達(dá)式主要是匹配0-199的數(shù)字

  4. (2[0-4]\d|25[0-5]|[01]?\d\d?)\.: 此表達(dá)式為匹配到0-255的數(shù)字,并在后面跟一個.

  5. ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}:此表達(dá)式為將上一步的表達(dá)式重復(fù)3次

至于后面的跟前面的一樣,就不分析了

7. 反義
代碼 說明
\W 匹配任意不是字母、數(shù)字、下劃線、漢字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非數(shù)字的字符
\B 匹配不是單詞開頭或者結(jié)束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou這幾個字母以外的任意字符
8. 向后引用

使用小括號指定一個子表達(dá)式后,匹配這個子表達(dá)式的文本可以在表達(dá)式或者其它程序中作進(jìn)一步的處理。默認(rèn)情況下,每個分組都會自動擁有一個組號,規(guī)則是:從左向右,以分組的左括號為標(biāo)志,第一個出現(xiàn)的分組的組號為1,第二個為2,以此類推。
向后引用用于重復(fù)搜索前面某個分組匹配的文本。如:\1,表示分組1匹配的文本

  • \b(\w+)\b\s+\1\b:可以用來匹配重復(fù)的單詞,如:go go或者kitty kitty。這個表達(dá)式首先是一個單詞,也就是單詞的開始處和結(jié)束處之間的多于一個的字母或者數(shù)字(\b(\w+)\b),這個單詞會被普貨到編號為1的分組中,然后是1個或幾個空白符(\s+),最后是分組1中捕獲的內(nèi)容(\1)

當(dāng)然也可以指定子表達(dá)式的組名。
要指定一個表達(dá)式的組名,需要使用這樣的語法:(?<Name>\w+)(或者把尖括號換成',即(?'Name'\w+)),這樣就把\w+的組名指定為Name了。要反向引用這個分組捕獲的內(nèi)容,可以使用\k<Name>,所以上一個栗子也可以寫成這樣紙:\b(?<Name>\w+)\b\s+\k<Name>\b

下表列出了小括號的一些常用的語法

分類 代碼 說明
捕獲 (exp) 匹配exp,并捕獲文本到自動命名的組里
捕獲 (?<name>exp) 匹配exp,并捕獲文本到名稱為name的組里,也可以寫成(?'name'exp)
捕獲 (?:exp) 匹配exp,不捕獲匹配的文本,也不給此分組分配組號
零寬斷言 (?=exp) 匹配exp前面的位置
零寬斷言 (?<=exp) 匹配exp后面的位置
零寬斷言 (?!exp) 匹配后面跟的不是exp的位置
零寬斷言 (?<!exp) 匹配前面不是exp的位置
注釋 (?#comment) 這種類型的分組不對正則表達(dá)式的處理產(chǎn)生任何影響,用于提供注釋讓人閱讀

我們已經(jīng)討論了前兩種語法。第三個(?:exp)不會改變正則表達(dá)式的處理方式,只是這樣的組匹配的內(nèi)容不會像前兩種那樣被捕獲到某個組里面,也不會擁有組號。

9. 零寬斷言

上表中的四個零寬斷言用于查找在某些內(nèi)容(但并不包括這些內(nèi)容)之前或者之后的東西,也就是說它們像\b、^$那樣用于指定一個位置,這個位置應(yīng)該滿足一定的條件(即斷言),因此它們也被稱為零寬斷言。
??

(?=exp)也叫零寬度正預(yù)測先行斷言,它斷言自身出現(xiàn)的位置的后面能匹配表達(dá)式exp。如:\b\w+(?=ing\b),匹配ing結(jié)尾的單詞的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.時,它會匹配singdanc。
(?<=exp)也叫零寬度正回顧后發(fā)斷言,它斷言自身出現(xiàn)的位置的前面能匹配表達(dá)式exp。如:(?<=\bre)\w+\b會匹配re開頭的單詞的后半部分(除了re以外的部分),如查找reading a book時,它匹配ading。
(?<=\s)\d+(?=\s)匹配以空白符間隔的數(shù)字(不包括這些空白符)

10. 負(fù)向零寬斷言

(?!exp)也叫零寬度負(fù)預(yù)測先行斷言,它斷言此位置的后面不能匹配表達(dá)式exp。
(?<!exp)也叫零寬度負(fù)回顧后發(fā)斷言,它**斷言此位置的前面不能匹配表達(dá)式exp。
??

  • \d{3}(?!\d):匹配三位數(shù)字,并且這三位數(shù)字后面不能是數(shù)字
  • \b((?!abc)\w)+\b:匹配不包含連續(xù)字符串abc的單詞
  • (?<![a-z])\d{7}:匹配前面不是小寫字母的七位數(shù)字
  • (?<=<(\w+)>).*(?=<\/\1>):匹配不包含屬性的簡單HTML標(biāo)簽里的內(nèi)容。分析:(?<=<(\w+)>)指定了這樣的前綴:被尖括號括起來的單詞(比如可能是<b>),然后是.*:任意的字符串,最后是一個后綴(?=<\/\1>),注意后綴中的\/,它是前面介紹過的字符轉(zhuǎn)義;\1則是一個反向引用,引用的正式捕獲的第一組,前面的(\w+)匹配的內(nèi)容,這樣前綴實際上是<b>的話,后綴就是</b>
11. 注釋

小括號的另一種用途是通過語法(?#comment)來包含注釋。如:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)。

12. 貪婪與懶惰

a.*b:將會匹配最長的以a開始,以b結(jié)束的字符串。如果用此表達(dá)式搜索匹配aabab,它會匹配整個字符串aabab。這被稱為貪婪匹配

有時,我們更需要懶惰匹配,也就是匹配盡可能少的字符。以上個例子為準(zhǔn),我們只需要在其后面加上一個問號?,這樣,.*?就意味著匹配任意數(shù)量的重復(fù)、但是在能使整個匹配成功的前提下使用最少的重復(fù)。

  • a.*?b:匹配最短的,以a開始,以b結(jié)束的字符串。如果應(yīng)用于aabab的話,它會匹配aab(第1-3個字符)和ab(第4-5個字符)。
    注意:為什么匹配到的第一個是aab(1-3)而不是ab(2-3)。簡單說,正則表達(dá)式有一條規(guī)則比懶惰/貪婪規(guī)則的優(yōu)先級更高:最先開始的匹配擁有最高的優(yōu)先權(quán)
    下表為懶惰限定符
代碼 說明
*? 重復(fù)任意次,但盡可能少重復(fù)
+? 重復(fù)1次或者更多次,但盡可能少重復(fù)
?? 重復(fù)0次或者1次,但盡可能少重復(fù)
{n,m}? 重復(fù)n到m次,但盡可能少重復(fù)
{n,}? 重復(fù)n次以上,但盡可能少重復(fù)

以上這些關(guān)于正則表達(dá)式的介紹已經(jīng)足以讓我們編寫、改寫、讀懂一些常見的正則表達(dá)式,希望以上的介紹能夠幫助到你。

3. 關(guān)于正則表達(dá)式的學(xué)習(xí)

正則表達(dá)式的學(xué)習(xí)最重要的就是栗子,我們可以從不同的案例切入,理解案例并對其修改、實驗(僅代表個人觀點,有更好的觀點可以和大家一起分享)。
關(guān)于測試:網(wǎng)上可以找到一些在線正則表達(dá)式測試的,童鞋們可以在那里測試驗證自己寫的一些表達(dá)式。

參考來源

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容