1. 程式人生 > >java 正則表示式 非捕獲組(特殊構造

java 正則表示式 非捕獲組(特殊構造

在 java api 文件中的正則表示式關於特殊構造(非捕獲組)的說明看不懂。例如:(?:X) X,作為非捕獲組
(?idmsux-idmsux) Nothing,但是將匹配標誌由 on 轉為 off
(?idmsux-idmsux:X) X,作為帶有給定標誌 on - off 的非捕獲組
(?=X) X,通過零寬度的正 lookahead
(?!X) X,通過零寬度的負 lookahead
(?<=X) X,通過零寬度的正 lookbehind
(?<!X) X,通過零寬度的負 lookbehind
(?>X) X,作為獨立的非捕獲組


這些字都說的很抽象。不懂……。還是搜尋下去。找到 火龍果 的解釋如下:

以 (? 開頭,) 結尾的都稱為非捕獲組,在匹配完成後在記憶體中不保留匹配到的字元。

非捕獲組的應用比較複雜,這裡只能簡單地說一下它們的意思。

1、(?:X) X,作為非捕獲組
與捕獲組 ( ) 的意思一樣也是將其作為一組進行處理,與捕獲組的區別在於不捕獲匹配的文字,
僅僅作為分組。
比如:要匹配 123123 這個,就可以寫為 (123)\1 使用反向引用,這時只能用捕獲組,在匹配
123 後會保留在記憶體中,便於反向引用,而 (?:123) 在匹配完後則不會保留,區別僅在於此。

2、(?idmsux-idmsux) Nothing,但是將匹配標誌i d m s u x on - off
用於標誌匹配,比如:表示式 (?i)abc(?-i)def 這時,(?i) 開啟不區分大小寫開關,abc 匹配
不區分大小地進行匹配,(?-i) 關閉標誌,恢復不區分大小寫,這時的 def 只能匹配 def

3、(?idmsux-idmsux:X) X,作為帶有給定標誌 i d m s u x on - off
與上面的類似,上面的表示式,可以改寫成為:(?i:abc)def,或者 (?i)abc(?-i:def)

4、(?=X) X,通過零寬度的正 lookahead
5、(?!X) X,通過零寬度的負 lookahead
(?=X) 表示當前位置(即字元的縫隙)後面允許出現的字元,比如:表示式 a(?=b),在字串為
ab 時,可能匹配 a,後面的 (?=b) 表示,a 後面的縫隙,可以看作是零寬度。
(?!X) 表示當前位置後面不允許出現的字元

6、(? <=X) X,通過零寬度的正 lookbehind
7、(? <!X) X,通過零寬度的負 lookbehind
這兩個與上面兩個類似,上面兩個是向後看,這個是向前看

8、(?>X) X,作為獨立的非捕獲組
匹配成功不進行回溯,這個比較複雜,也侵佔量詞“+”可以通用,比如:\d++ 可以寫為 (?>\d+)。

我認為,第1、2、3點比較好理解,4、5、6、7看類懂,還是用示例來說明:從“aacabab”找a,且後面只允許出現b。程式碼如下:
Pattern p = Pattern.compile("a(?=b)");
Matcher m = p.matcher("aacabab");
while(m.find()) {
    System.out.println(m.group()+", start="+m.start()+", end="+m.end());
}

執行結果:
a, start=3, end=4
a, start=5, end=6

個人理解:在(?=b)這個“式”後面允許出現b,且這個“式”不佔正則表示式位置(所謂0寬度),lookahead 的意思是b字元的前面,它前面緊接著是a,也就是a後面出現b。

其中說的示例:來看 /\b(integer|insert|in)\b/ 匹配 integers 過程,第一個,當integer\b匹配到s時失敗,然後字串(integers)會回溯到i,再接著第二個(insert)去匹配。而把模式寫成 /\b(?>integer|insert|in)\b/ 在剛才的第一個匹配失敗,字串(integers)不會回溯了,也不會有第二個去匹配了,所有速度會快一點點。

但是寫 (?>X) 這種式子時要注意,是從左到右看的。/\b(?>integer|insert|in)\b/ ,與 /\b(?>in|integer|insert)\b/ 去匹配 insert,結果會不一樣,前者可以匹配到,後者不能,什麼原因自己分析下。一但匹配失敗就會跳過,所以應該長的寫在表示式前面。