JAVA正則表示式高階用法(分組與捕獲)
正則表示式在字串處理中經常使用,關於正則簡單的用法相信有一點程式基礎的人都懂得一些,這裡就不介紹簡單基礎了。這裡主要講解一下在JAVA中實現了的正則的高階用法-分組與捕獲。
對於要重複單個字元,非常簡單,直接在字元後賣弄加上限定符即可,例如 a+ 表示匹配1個或一個以上的a,a?表示匹配0個或1個a。這些限定符如下所示:
X? | X,一次或一次也沒有 |
X* | X,零次或多次 |
X+ | X,一次或多次 |
X{n} | X,恰好 n 次 |
X{n,} | X,至少 n 次 |
X{n,m} |
X,至少 n 次,但是不超過 m 次 |
但是我們如果要對多個字元進行重複怎麼辦呢?此時我們就要用到分組,我們可以使用小括號"()"來指定要重複的子表示式,然後對這個子表示式進行重複,例如:(abc)? 表示0個或1個abc 這裡一
分組可以分為兩種形式,捕獲組和非捕獲組。
捕獲組
捕獲組可以通過從左到右計算其開括號來編號。例如,在表示式 ((A)(B(C))) 中,存在四個這樣的組:
1 ((A)(B(C))) 2 /A 3 (B(C)) 4 (C)
組零始終代表整個表示式
之所以這樣命名捕獲組是因為在匹配中,儲存了與這些組匹配的輸入序列的每個子序列。捕獲的子序列稍後可以通過 Back 引用在表示式中使用,也可以在匹配操作完成後從匹配器檢索。
Back 引用 是說在後面的表示式中我們可以使用組的編號來引用前面的表示式所捕獲到的文字序列(是文字不是正則)
例如 ([" ']).* /1 其中使用了分組,/1就是對引號這個分組的引用,它匹配包含在兩個引號或者兩個單引號中的所有字串,如,"abc" 或 " ' " 或 ' " ' ,但是請注意,它並不會對" a'或者 'a"匹配。原因上面已經說明,Back引用只是引用文字而不是表示式。
非捕獲組
以 (?) 開頭的組是純的非捕獲 組,它不捕獲文字,也不針對組合計進行計數。就是說,如果小括號中以?號開頭,那麼這個分組就不會捕獲文字,當然也不會有組的編號,因此也不存在Back 引用。
在Java中,支援的非捕獲組,有如下幾種:
(?=X) | X,通過零寬度的正 lookahead |
(?!X) | X,通過零寬度的負 lookahead |
(?<=X) | X,通過零寬度的正 lookbehind |
(?<!X) | X,通過零寬度的負 lookbehind |
這四個非捕獲組用於匹配表示式X,但是不包含表示式的文字。
(?=X ) | 零寬度正先行斷言。僅當子表示式 X 在 此位置的右側匹配時才繼續匹配。例如,/w+(?=/d) 與後跟數字的單詞匹配,而不與該數字匹配。此構造不會回溯。 |
(?!X) | 零寬度負先行斷言。僅當子表示式 X 不在 此位置的右側匹配時才繼續匹配。例如,例如,/w+(?!/d) 與後不跟數字的單詞匹配,而不與該數字匹配。 |
(?<=X) | 零寬度正後發斷言。僅當子表示式 X 在 此位置的左側匹配時才繼續匹配。例如,(?<=19)99 與跟在 19 後面的 99 的例項匹配。此構造不會回溯。 |
(?<!X) | 零寬度負後發斷言。僅當子表示式 X 不在此位置的左側匹配時才繼續匹配。例如,(?<!19)99 與不跟在 19 後面的 99 的例項匹配 |
一般來說要如果是要對一個字元組合採用否定判定時一般都會用上先行斷言和後發斷言。例如左邊不能包含1302和1301的字串,因為你沒法使用某種方式來否定一個1302四個字元的組合(注意:[^(1302)|(1301)]表示不能是1或者3或者0或者2,而不是1302一個整體),只有先行或者後發斷言可以表示一個整體 : 456(?<!1302|1301)789.
舉例:
上面都是理論性的介紹,這裡就使用一些例子來說明一下問題:
1、測試匹配性 (?<!4)56(?=9) 這裡的含義就是匹配後面的文字56前面不能是4,後面必須是9組成。因此,可以匹配如下文字 5569 ,與4569不匹配。
2 、提取字串 提取 da12bka3434bdca4343bdca234bm 提取包含在字元a和b之間的數字,但是這個a之前的字元不能是c,b後面的字元必須是d才能提取。
例如這裡就只有3434這個數字滿足要求。那麼我們怎麼提取呢?
首先我們寫出提取這個字串的表示式: (?<!c)a(/d+)bd 這裡就只有一個捕獲組(/d+)
JAVA程式碼片段如下:
- Pattern p = Pattern.compile();
- Matcher m = p.matcher("da12bka3434bdca4343bdca234bm");
- while(m.find()){
- System.out.println(m.group(1)); //我們只要捕獲組1的數字即可。結果 3434
- System.out.println(m.group(0)); // 0組是整個表示式,看這裡,並沒有提煉出(?<!c)的字元 。結果 a3434bd
- }
可以看到,非捕獲組,最後是不會返回結果的,因為它本身並不捕獲文字。
正則表示式功能其實非常強大,這裡只是對高階用法的簡單探討。有興趣的朋友和本人共同討論。