1 ?????? ? 概述
1.1 ???? 什么是捕獲組
捕獲組就是把正則表達(dá)式中子表達(dá)式匹配的內(nèi)容,保存到內(nèi)存中以數(shù)字編號(hào)或顯式命名的組里,方便后面引用。當(dāng)然,這種引用既可以是在正則表達(dá)式內(nèi)部,也可以是在正則表達(dá)式外部。
捕獲組有兩種形式,一種是普通捕獲組,另一種是命名捕獲組,通常所說的捕獲組指的是普通捕獲組。語(yǔ)法如下:
普通捕獲組: (Expression)
命名捕獲組: (?<name>Expression)
普通捕獲組在大多數(shù)支持正則表達(dá)式的語(yǔ)言或工具中都是支持的,而命名捕獲組目前只有 .NET 、 PHP 、 Python 等部分語(yǔ)言支持,據(jù)說 Java 會(huì)在 7.0 中提供對(duì)這一特性的支持。上面給出的命名捕獲組的語(yǔ)法是 .NET 中的語(yǔ)法,另外在 .NET 中使用 (?’name’Expression) 與使用 (?<name>Expression) 是等價(jià)的。在 PHP 和 Python 中命名捕獲組語(yǔ)法為: (?P<name>Expression) 。
另外需要說明的一點(diǎn)是,除 (Expression) 和 (?<name>Expression) 語(yǔ)法外,其它的 (?...) 語(yǔ)法都不是捕獲組。
1.2 ???? 捕獲組編號(hào)規(guī)則
編號(hào)規(guī)則指的是以數(shù)字為捕獲組進(jìn)行編號(hào)的規(guī)則,在普通捕獲組或命名捕獲組單獨(dú)出現(xiàn)的正則表達(dá)式中,編號(hào)規(guī)則比較清晰,在普通捕獲組與命名捕獲組混合出現(xiàn)的正則表達(dá)式中,捕獲組的編號(hào)規(guī)則稍顯復(fù)雜。
在展開討論之前,需要說明的是,編號(hào)為 0 的捕獲組,指的是正則表達(dá)式整體,這一規(guī)則在支持捕獲組的語(yǔ)言中,基本上都是適用的。下面對(duì)其它編號(hào)規(guī)則逐一展開討論。
1.2.1 ? 普通捕獲組編號(hào)規(guī)則
如果沒有顯式為捕獲組命名,即沒有使用命名捕獲組,那么需要按數(shù)字順序來(lái)訪問所有捕獲組。在只有普通捕獲組的情況下,捕獲組的編號(hào)是按照“ ( ”出現(xiàn)的順序,從左到右,從 1 開始進(jìn)行編號(hào)的 。
正則表達(dá)式: (/d{4})-(/d{2}-(/d/d))
上面的正則表達(dá)式可以用來(lái)匹配格式為 yyyy-MM-dd 的日期,為了在下表中得以區(qū)分,月和日分別采用了 /d{2} 和 /d/d 這兩種寫法。
用以上正則表達(dá)式匹配字符串: 2008-12-31 ,匹配結(jié)果為:
?
編號(hào) |
命名 |
捕獲組 |
匹配內(nèi)容 |
0 |
? |
(/d{4})-(/d{2}-(/d/d)) |
2008-12-31 |
1 |
? |
(/d{4}) |
2008 |
2 |
? |
(/d{2}-(/d/d)) |
12-31 |
3 |
? |
(/d/d) |
31 |
?
1.2.2 ? 命名捕獲組編號(hào)規(guī)則
命名捕獲組通過顯式命名,可以通過組名方便的訪問到指定的組,而不需要去一個(gè)個(gè)的數(shù)編號(hào),同時(shí)避免了在正則表達(dá)式擴(kuò)展過程中,捕獲組的增加或減少對(duì)引用結(jié)果導(dǎo)致的不可控。
不過容易忽略的是,命名捕獲組也參與了編號(hào)的,在只有命名捕獲組的情況下,捕獲組的編號(hào)也是按照“ ( ”出現(xiàn)的順序,從左到右,從 1 開始進(jìn)行編號(hào)的 。
正則表達(dá)式: (?<year>/d{4})-(?<date>/d{2}-(?<day>/d/d))
?
用以上正則表達(dá)式匹配字符串: 2008-12-31
匹配結(jié)果為:
?
編號(hào) |
命名 |
捕獲組 |
匹配內(nèi)容 |
0 |
? |
(?<year>/d{4})-(?<date>/d{2}-(?<day>/d/d)) |
2008-12-31 |
1 |
year |
(?<year>/d{4}) |
2008 |
2 |
date |
(?<date>/d{2}-(?<day>/d/d)) |
12-31 |
3 |
day |
(?<day>/d/d) |
31 |
?
1.2.3 ? 普通捕獲組與命名捕獲組混合編號(hào)規(guī)則
當(dāng)一個(gè)正則表達(dá)式中,普通捕獲組與命名捕獲組混合出現(xiàn)時(shí),捕獲組的編號(hào)規(guī)則稍顯復(fù)雜。對(duì)于其中的命名捕獲組,隨時(shí)都可以通過組名進(jìn)行訪問,而對(duì)于普通捕獲組,則只能通過確定其編號(hào)后進(jìn)行訪問。
混合方式的捕獲組編號(hào),首先按照普通捕獲組中“ ( ”出現(xiàn)的先后順序,從左到右,從 1 開始進(jìn)行編號(hào),當(dāng)普通捕獲組編號(hào)完成后,再按命名捕獲組中“ ( ”出現(xiàn)的先后順序,從左到右,接著普通捕獲組的編號(hào)值繼續(xù)進(jìn)行編號(hào)。
也就是先忽略命名捕獲組,對(duì)普通捕獲組進(jìn)行編號(hào),當(dāng)普通捕獲組完成編號(hào)后,再對(duì)命名捕獲組進(jìn)行編號(hào)。
正則表達(dá)式: (/d{4})-(?<date>/d{2}-(/d/d))
?
用以上正則表達(dá)式匹配字符串: 2008-12-31 ,匹配結(jié)果為:
?
編號(hào) |
命名 |
捕獲組 |
匹配內(nèi)容 |
0 |
? |
(/d{4})-(?<date>/d{2}-(/d/d)) |
2008-12-31 |
1 |
? |
(/d{4}) |
2008 |
3 |
date |
(?<date>/d{2}-(/d/d)) |
12-31 |
2 |
? |
(/d/d) |
31 |
?
2 ?????? 捕獲組的引用
對(duì)捕獲組的引用一般有以下幾種:
1) ?????? 正則表達(dá)式中,對(duì)前面捕獲組捕獲的內(nèi)容進(jìn)行引用,稱為反向引用;
2) ?????? 正則表達(dá)式中, (?(name)yes|no) 的條件判斷結(jié)構(gòu);
3) ?????? 在程序中,對(duì)捕獲組捕獲內(nèi)容的引用。
2.1 ???? 反向引用
捕獲組捕獲到的內(nèi)容,不僅可以在正則表達(dá)式外部通過程序進(jìn)行引用,也可以在正則表達(dá)式內(nèi)部進(jìn)行引用,這種引用方式就是反向引用。
反向引用的作用通常是用來(lái)查找或限定重復(fù),限定指定標(biāo)識(shí)配對(duì)出現(xiàn)等等。
對(duì)于普通捕獲組和命名捕獲組的引用,語(yǔ)法如下:
普通捕獲組反向引用: /k<number> ,通常簡(jiǎn)寫為 /number
命名捕獲組反向引用: /k<name> 或者 /k'name'
普通捕獲組反向引用中 number 是十進(jìn)制的數(shù)字,即捕獲組的編號(hào);命名捕獲組反向引用中的 name 為命名捕獲組的組名。
反向引用涉及到的內(nèi)容比較多,后續(xù)單獨(dú)說明。
2.2 ???? 條件判斷表達(dá)式
條件判斷結(jié)構(gòu)在平衡組中談到過,基本應(yīng)用和擴(kuò)展應(yīng)用都可以在其中找到例子,這里不再贅述,請(qǐng)參考 .NET 正則基礎(chǔ)之 —— 平衡組 。
2.3 ???? 程序中引用
根據(jù)語(yǔ)言的不同,程序中對(duì)捕獲組引用的方式也有所不同,下面就 JavaScript 和 .NET 進(jìn)行舉例說明。
2.3.1 ? JavaScript 中的引用
由于 JavaScript 中不支持命名捕獲組,所以對(duì)于捕獲組的引用就只支持普通捕獲組的反向引用和 $number 方式的引用。程序中的引用一般在替換和匹配時(shí)使用。
注: 以下應(yīng)用舉例僅考慮簡(jiǎn)單應(yīng)用場(chǎng)景,對(duì)于 < a href ="javascript:document.write('<b>hello</b>')"/> 這種復(fù)雜場(chǎng)景暫不考慮。
1) ???????? 在 Replace 中引用,通常是通過 $number 方式引用。
舉例: 替換掉 html 標(biāo)簽中的屬性。
< textarea id = "result" rows = "10" cols = "100" ></ textarea >
< script type = "text/javascript" >
var data = "<table id=/"test/"><tr class=/"light/"><td> test </td></tr></table>" ;
var reg = /<([a-z]+)[^>]*>/ig;
document.getElementById( "result" ).value = data.replace(reg, "<$1>" );
</ script >
// 輸出
<table><tr><td> test </td></tr></table>
2) ???????? 在匹配時(shí)的引用,通常通過 RegExp.$number 方式引用。
舉例: 同時(shí)獲取 <img…> 中的 src 和 name 屬性值,屬性的順序不固定。參考 一條正則能不能同時(shí)取出一個(gè) img 標(biāo)記的 src 和 name?
?
- <textarea?id= "result" ?rows= "10" ?cols= "100" ></textarea>???
- <script?type= "text/javascript" >???
- var ?data?=?[ '?<img?alt=""?border="0"?name="g6-o44-1"?onload="DrawImage"?src="/bmp/foo1.jpg"?/>' ,? '?<img?src="/bmp/foo2.jpg"?alt=""?border="0"?name="g6-o44-2"?onload="DrawImage"?/>' ]?;??
- var ?reg?=?/<img/b(?=(?:(?!name=).)*name=([ '"]?)([^' "/s>]+)/1)(?:(?!src=).)*src=([ '"]?)([^' "/s>]+)/3[^>]*>/i;??
- for ( var ?i=0;i<data.length;i++)??
- {??
- ???? var ?s?=?data[i];??
- ????document.getElementById( "result" ).value?+=? "源字符串:" ?+?s?+? "/n" ;??
- ????document.write( "<br?/>" );??
- ???? if (reg.test(s))??
- ????{??
- ????????document.getElementById( "result" ).value?+=? "name:?" ?+?RegExp.$2?+? "/n" ;??
- ????????document.getElementById( "result" ).value?+=? "src:?" ?+?RegExp.$4?+? "/n" ;??
- ????}??
- }??
- </script>??
<script type="text/javascript"></script>
?
?
?
2.3.2 ? .NET 中的引用
由于 .NET 支持命名捕獲組,所以在 .NET 中的引用方式會(huì)多一些。通常也是在兩種場(chǎng)景下應(yīng)用,一是替換,一是匹配。
1) ???????? 替換中的引用
普通捕獲組: $number
命名捕獲組: ${name}
替換中應(yīng)用,仍是上面的例子。
2) ???????? 匹配后的引用
對(duì)于匹配結(jié)果中捕獲組捕獲內(nèi)容的引用,可以通過 Groups 和 Result 對(duì)象進(jìn)行引用。
對(duì)于捕獲組 0 的引用,可以簡(jiǎn)寫作 m.Value 。
轉(zhuǎn)自:http://blog.csdn.net/lxcnn/article/details/4146148
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
