轉(zhuǎn) http://extjs2.javaeye.com/blog/394128
正則表達(dá)式在字符串處理中經(jīng)常使用,關(guān)于正則簡單的用法相信有一點(diǎn)程序基礎(chǔ)的人都懂得一些,這里就不介紹簡單基礎(chǔ)了。這里主要講解一下在JAVA中實(shí)現(xiàn)了的正則的高級(jí)用法-分組與捕獲。
對于要重復(fù)單個(gè)字符,非常簡單,直接在字符后賣弄加上限定符即可,例如 a+ 表示匹配1個(gè)或一個(gè)以上的a,a?表示匹配0個(gè)或1個(gè)a。這些限定符如下所示:
X? X,一次或一次也沒有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超過 m 次
但是我們?nèi)绻獙Χ鄠€(gè)字符進(jìn)行重復(fù)怎么辦呢?此時(shí)我們就要用到分組,我們可以使用小括號(hào)"()"來指定要重復(fù)的子表達(dá)式,然后對這個(gè)子表達(dá)式進(jìn)行重復(fù),例如:(abc)? 表示0個(gè)或1個(gè)abc 這里一個(gè)括號(hào)的表達(dá)式就表示一個(gè)分組。
分組可以分為兩種形式,捕獲組和非捕獲組。
捕獲組
捕獲組可以通過從左到右計(jì)算其開括號(hào)來編號(hào)。例如,在表達(dá)式 ((A)(B(C))) 中,存在四個(gè)這樣的組:
1 ((A)(B(C)))
2 \A
3 (B(C))
4 (C)
組零始終代表整個(gè)表達(dá)式
之所以這樣命名捕獲組是因?yàn)樵谄ヅ渲校4媪伺c這些組匹配的輸入序列的每個(gè)子序列。捕獲的子序列稍后可以通過 Back 引用在表達(dá)式中使用,也可以在匹配操作完成后從匹配器檢索。
Back 引用 是說在后面的表達(dá)式中我們可以使用組的編號(hào)來引用前面的表達(dá)式所捕獲到的文本序列(是文本不是正則)。
例如 ([" ']).* \1 其中使用了分組,\1就是對引號(hào)這個(gè)分組的引用,它匹配包含在兩個(gè)引號(hào)或者兩個(gè)單引號(hào)中的所有字符串,如,"abc" 或 " ' " 或 ' " ' ,但是請注意,它并不會(huì)對" a'或者 'a"匹配。原因上面已經(jīng)說明,Back引用只是引用文本而不是表達(dá)式。
非捕獲組
以 (?) 開頭的組是純的非捕獲 組,它不捕獲文本,也不針對組合計(jì)進(jìn)行計(jì)數(shù)。就是說,如果小括號(hào)中以?號(hào)開頭,那么這個(gè)分組就不會(huì)捕獲文本,當(dāng)然也不會(huì)有組的編號(hào),因此也不存在Back 引用。
在Java中,支持的非捕獲組,有如下幾種:
(?=X) X,通過零寬度的正 lookahead
(?!X) X,通過零寬度的負(fù) lookahead
(?<=X) X,通過零寬度的正 lookbehind
(?<!X) X,通過零寬度的負(fù) lookbehind
這四個(gè)非捕獲組用于匹配表達(dá)式X,但是不包含表達(dá)式的文本。
(?=X ) 零寬度正先行斷言。僅當(dāng)子表達(dá)式 X 在 此位置的右側(cè)匹配時(shí)才繼續(xù)匹配。例如,\w+(?=\d) 與后跟數(shù)字的單詞匹配,而不與該數(shù)字匹配。此構(gòu)造不會(huì)回溯。
(?!X) 零寬度負(fù)先行斷言。僅當(dāng)子表達(dá)式 X 不在 此位置的右側(cè)匹配時(shí)才繼續(xù)匹配。例如,例如,\w+(?!\d) 與后不跟數(shù)字的單詞匹配,而不與該數(shù)字匹配。
(?<=X) 零寬度正后發(fā)斷言。僅當(dāng)子表達(dá)式 X 在 此位置的左側(cè)匹配時(shí)才繼續(xù)匹配。例如,(?<=19)99 與跟在 19 后面的 99 的實(shí)例匹配。此構(gòu)造不會(huì)回溯。
(?<!X) 零寬度負(fù)后發(fā)斷言。僅當(dāng)子表達(dá)式 X 不在此位置的左側(cè)匹配時(shí)才繼續(xù)匹配。例如,(?<!19)99 與不跟在 19 后面的 99 的實(shí)例匹配
舉例:
上面都是理論性的介紹,這里就使用一些例子來說明一下問題:
1、測試匹配性 (?<!4)56(?=9) 這里的含義就是匹配后面的文本56前面不能是4,后面必須是9組成。因此,可以匹配如下文本 5569 ,與4569不匹配。
2 、提取字符串 提取 da12bka3434bdca4343bdca234bm 提取包含在字符a和b之間的數(shù)字,但是這個(gè)a之前的字符不能是c,b后面的字符必須是d才能提取。
例如這里就只有3434這個(gè)數(shù)字滿足要求。那么我們怎么提取呢?
首先我們寫出提取這個(gè)字符串的表達(dá)式: (?<!c)a(\d+)bd 這里就只有一個(gè)捕獲組(\d+)
JAVA代碼片段如下:
Pattern p = Pattern.compile("(?<!c)a(\\d+)bd");
Matcher m = p.matcher("da12bca3434bdca4343bdca234bm");
while(m.find()){
System.out.println(m.group(1)); //我們只要捕獲組1的數(shù)字即可。結(jié)果 3434
System.out.println(m.group(0)); // 0組是整個(gè)表達(dá)式,看這里,并沒有提煉出(?<!c)的字符 。結(jié)果 a3434bd
}
可以看到,非捕獲組,最后是不會(huì)返回結(jié)果的,因?yàn)樗旧聿⒉徊东@文本。
正則表達(dá)式在字符串處理中經(jīng)常使用,關(guān)于正則簡單的用法相信有一點(diǎn)程序基礎(chǔ)的人都懂得一些,這里就不介紹簡單基礎(chǔ)了。這里主要講解一下在JAVA中實(shí)現(xiàn)了的正則的高級(jí)用法-分組與捕獲。
對于要重復(fù)單個(gè)字符,非常簡單,直接在字符后賣弄加上限定符即可,例如 a+ 表示匹配1個(gè)或一個(gè)以上的a,a?表示匹配0個(gè)或1個(gè)a。這些限定符如下所示:
X? X,一次或一次也沒有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超過 m 次
但是我們?nèi)绻獙Χ鄠€(gè)字符進(jìn)行重復(fù)怎么辦呢?此時(shí)我們就要用到分組,我們可以使用小括號(hào)"()"來指定要重復(fù)的子表達(dá)式,然后對這個(gè)子表達(dá)式進(jìn)行重復(fù),例如:(abc)? 表示0個(gè)或1個(gè)abc 這里一個(gè)括號(hào)的表達(dá)式就表示一個(gè)分組。
分組可以分為兩種形式,捕獲組和非捕獲組。
捕獲組
捕獲組可以通過從左到右計(jì)算其開括號(hào)來編號(hào)。例如,在表達(dá)式 ((A)(B(C))) 中,存在四個(gè)這樣的組:
1 ((A)(B(C)))
2 \A
3 (B(C))
4 (C)
組零始終代表整個(gè)表達(dá)式
之所以這樣命名捕獲組是因?yàn)樵谄ヅ渲校4媪伺c這些組匹配的輸入序列的每個(gè)子序列。捕獲的子序列稍后可以通過 Back 引用在表達(dá)式中使用,也可以在匹配操作完成后從匹配器檢索。
Back 引用 是說在后面的表達(dá)式中我們可以使用組的編號(hào)來引用前面的表達(dá)式所捕獲到的文本序列(是文本不是正則)。
例如 ([" ']).* \1 其中使用了分組,\1就是對引號(hào)這個(gè)分組的引用,它匹配包含在兩個(gè)引號(hào)或者兩個(gè)單引號(hào)中的所有字符串,如,"abc" 或 " ' " 或 ' " ' ,但是請注意,它并不會(huì)對" a'或者 'a"匹配。原因上面已經(jīng)說明,Back引用只是引用文本而不是表達(dá)式。
非捕獲組
以 (?) 開頭的組是純的非捕獲 組,它不捕獲文本,也不針對組合計(jì)進(jìn)行計(jì)數(shù)。就是說,如果小括號(hào)中以?號(hào)開頭,那么這個(gè)分組就不會(huì)捕獲文本,當(dāng)然也不會(huì)有組的編號(hào),因此也不存在Back 引用。
在Java中,支持的非捕獲組,有如下幾種:
(?=X) X,通過零寬度的正 lookahead
(?!X) X,通過零寬度的負(fù) lookahead
(?<=X) X,通過零寬度的正 lookbehind
(?<!X) X,通過零寬度的負(fù) lookbehind
這四個(gè)非捕獲組用于匹配表達(dá)式X,但是不包含表達(dá)式的文本。
(?=X ) 零寬度正先行斷言。僅當(dāng)子表達(dá)式 X 在 此位置的右側(cè)匹配時(shí)才繼續(xù)匹配。例如,\w+(?=\d) 與后跟數(shù)字的單詞匹配,而不與該數(shù)字匹配。此構(gòu)造不會(huì)回溯。
(?!X) 零寬度負(fù)先行斷言。僅當(dāng)子表達(dá)式 X 不在 此位置的右側(cè)匹配時(shí)才繼續(xù)匹配。例如,例如,\w+(?!\d) 與后不跟數(shù)字的單詞匹配,而不與該數(shù)字匹配。
(?<=X) 零寬度正后發(fā)斷言。僅當(dāng)子表達(dá)式 X 在 此位置的左側(cè)匹配時(shí)才繼續(xù)匹配。例如,(?<=19)99 與跟在 19 后面的 99 的實(shí)例匹配。此構(gòu)造不會(huì)回溯。
(?<!X) 零寬度負(fù)后發(fā)斷言。僅當(dāng)子表達(dá)式 X 不在此位置的左側(cè)匹配時(shí)才繼續(xù)匹配。例如,(?<!19)99 與不跟在 19 后面的 99 的實(shí)例匹配
舉例:
上面都是理論性的介紹,這里就使用一些例子來說明一下問題:
1、測試匹配性 (?<!4)56(?=9) 這里的含義就是匹配后面的文本56前面不能是4,后面必須是9組成。因此,可以匹配如下文本 5569 ,與4569不匹配。
2 、提取字符串 提取 da12bka3434bdca4343bdca234bm 提取包含在字符a和b之間的數(shù)字,但是這個(gè)a之前的字符不能是c,b后面的字符必須是d才能提取。
例如這里就只有3434這個(gè)數(shù)字滿足要求。那么我們怎么提取呢?
首先我們寫出提取這個(gè)字符串的表達(dá)式: (?<!c)a(\d+)bd 這里就只有一個(gè)捕獲組(\d+)
JAVA代碼片段如下:
Pattern p = Pattern.compile("(?<!c)a(\\d+)bd");
Matcher m = p.matcher("da12bca3434bdca4343bdca234bm");
while(m.find()){
System.out.println(m.group(1)); //我們只要捕獲組1的數(shù)字即可。結(jié)果 3434
System.out.println(m.group(0)); // 0組是整個(gè)表達(dá)式,看這里,并沒有提煉出(?<!c)的字符 。結(jié)果 a3434bd
}
可以看到,非捕獲組,最后是不會(huì)返回結(jié)果的,因?yàn)樗旧聿⒉徊东@文本。