解惑正則表達式中的捕獲

讀jQuery源碼,其中不可避免的要弄明白正則表達式,在此對非捕獲組(non-capturing)進行了一些梳理。正則表達式

關於捕獲的一些主要用法

  1. (?:X)
  2. (?=X)
  3. (?<=X)
  4. (?!X)
  5. (?<!X)

捕獲

要書明白捕獲,就要先從分組開始。重複單字符咱們可使用限定符,若是重複字符串,用什麼呢? 對!用小括號,小括號裏包裹指定字表達式(子串),這就是分組。以後就能夠限定這個子表示的重複次數了。學習

那麼,什麼是捕獲呢?使用小括號指定一個子表達式後,匹配這個子表達式的文本(即匹配的內容)能夠在表達式或者其餘過程當中接着用,怎麼用呢?至少應該有個指針啥的引用它吧? 對!默認狀況下,每一個分組(小括號)會自動spa

擁有一個組號,從左到右,以分組的左括號爲標誌,第一個出現的分組組號爲1,後續遞增。若是出現嵌套,指針

例如:code

「aabcd」orm

採用正則 (a(b))(c) match 結果入下:索引

分組 捕獲
$1(group1) ab
$2(group2) b
$3(group3) c

繼續漲姿式。ci

1、(?:)非捕獲組走起。unicode

由下面一個例子引起對非捕獲組的學習。文檔

有兩個金額:6000¥ 和 1000$。

需求是獲得金額和貨幣種類。

『廢話少說,多用正則』:

(\d+)+([$¥])

輸出結果爲:

OK,知足了要求。這裏的正則分紅了兩個組,一個是(d+),一個是(¥$),前一個組($1)匹配金額,後一個組($2)匹配貨幣種類。

如今,需求變了!! 我須要這個正則同時能夠匹配浮點數小數點前面的整數。如10010.86¥,提煉出 10010 和 ¥。

那麼正則以下:

(\d+)(\.?)(\d)([$¥])

這裏用括號分了四組,因此要輸出金額的整數部分和種類,要分別輸了$1,$4了。若是輸出部分和正則是分開的,我但願只修改正則而不去修改輸出部分的代碼,也就是仍是用$1,$2做爲輸出。由此能夠引出非捕獲組(?:)。

把前面的正則修改成:

(\d+)(?:\.?)(?:\d+)([¥$])$

這樣,仍是用$1,$2作爲輸出,一樣輸出了 10010 和 ¥

這個正則的中間兩個組用到的就是非捕獲組(?:),它能夠理解爲只分組而不捕獲。

2、(?=)和(?<=) 先後查找

有的資料把它們叫作確定式向前查找和確定式向後查找;

有的資料也叫作確定順序環視和確定逆序環視。

一、直接看下面的例子:

[0-9a-z]{2}(?=aa) var str = "12332aa438aaf";

Match List:

1 32
2 38

這個正則的意思是:匹配這麼一個字符串,它要知足:是兩位字符(數字,或字母),且後面緊跟着兩個a。

分析一下:

32aa 這個子串知足這個條件,因此能夠匹配到,又由於 (?=) 的部分是不捕獲的,因此輸出的只是 32,不包括aa。同理 38aa 也匹配這個正則,而輸出僅是 38。

再深刻看一下:

當str第一次匹配成功輸出 32 後,程序要繼續向後查找是否還有匹配的其它子串。那麼這時應該從 32aa 的後一位開始向後查找,仍是從 32 的後一位呢?也就是從索引 5 開始仍是從 7 開始呢?有人可能想到是從 32aa 的下一位開始日後找,由於 32aa 匹配了正則,因此下一位固然是它的後面也就是從 4 開始。但其實是從 32 的後一位也就是第一個 a 開始日後找。緣由仍是 (?=) 是非捕獲的。

查閱API文檔是這麼註釋的:

(?=X) X, via zero-width positive lookahead

可見zero-width(零寬度)說的就是這個意思。

如今,把字符串寫的更有意思些:str = "aaaaaaaa";

看一下它的輸出: aa aa aa

分析一下:

這個字符串一共有8個a。

第一次匹配比較容易找到,那就是前四個:aaaa ,固然第三和第四個 a 是不捕獲的,因此輸出是第一和第二個a;

接着繼續查找,這時是從第三個a開始,三到六,這4個a區配到了,因此輸出第三和第四個a;

接着繼續查找,這時是從第五個a開始,五到八,這4個a區配到了,因此輸出第五和第六個a;

接着日後查找,這時是從第七個a開始,顯然,第七和第八個a,不知足正則的匹配條件,查找結束。

咱們再延伸一下,剛說的狀況的是(?=)放在捕獲的字符串後面,它若是放在前面又是什麼結果呢?

例子換成:

(?=hopeful)hope

它的輸出是hope。

正則的意思是:是否能匹配hopeful,若是能,則捕獲hopeful中的hope。固然繼續向後查找匹配的子串,是從f開始。

比較一下能夠看出,(?=hopeful)hope 和 hope(?=ful),兩個正則的效果實際上是同樣的。

二、下面說一下 (?<=)

把正則改一下,

(?<=aa)[0-9a-z]{2};

字符串仍是str = "12332aa438aaf";

它的輸出:43。

這個正則的意思是:匹配這麼一個字符串,它要知足:是兩位字符(數字或字母),且前面緊跟的是兩個字母 a。

一樣,深刻一下,把str換成str = "aaaaaaaa";看一下輸出是什麼,一樣也是:aa aa aa

分析一下:

第一次匹配不用說,是前四個a,輸出的是第三和第四個a;

繼續向後查找,從第五個a開始,程序發現,第五個和第六個a知足,由於是兩位字符,且知足前面緊跟着兩個a(第三和第四個a)。因此匹配成功,輸出第五個和第六個a;

繼續向後查找,從第七個a開始,程序發現,第七個和第八個a知足,由於是兩位字符,且知足前面緊跟着兩個a(第五和第六個a)。因此匹配成功,輸出第七和第八個a。查找結束。

3、(?!)和(?<!) 逆襲!

從外觀上看,和前面一組很類似,區別就是把 ‘=’ 換成了 ‘!’

那麼意義恰好也是相反的。

[0-9a-z]{2}(?!aa)意思是:匹配兩個字符,且後面緊跟着的不是aa

(?<!aa)[0-9a-z]{2} 意思是:匹配兩個字符,且前面緊跟着的不是aa

用法和前面講的差很少,這裏再也不詳述。

相關文章
相關標籤/搜索