正則基礎(chǔ)之?捕獲組(capture?group)
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ù)字順序來訪問所有捕獲組。在只有普通捕獲組的情況下,捕獲組的編號(hào)是按照“(”出現(xiàn)的順序,從左到右,從1開始進(jìn)行編號(hào)的 。
正則表達(dá)式:(\d{4})-(\d{2}-(\d\d))
上面的正則表達(dá)式可以用來匹配格式為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)行引用,這種引用方式就是反向引用。
反向引用的作用通常是用來查找或限定重復(fù),限定指定標(biāo)識(shí)配對(duì)出現(xiàn)等等。
對(duì)于普通捕獲組和命名捕獲組的引用,語(yǔ)法如下:
普通捕獲組反向引用:\k<number>,通常簡(jiǎn)寫為\number
命名捕獲組反向引用:\k<name>或者\(yùn)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" οnlοad="DrawImage" src="/bmp/foo1.jpg" />', ' <img src="/bmp/foo2.jpg" alt="" border="0" name="g6-o44-2" οnlοad="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>
2.3.2 .NET中的引用
由于.NET支持命名捕獲組,所以在.NET中的引用方式會(huì)多一些。通常也是在兩種場(chǎng)景下應(yīng)用,一是替換,一是匹配。
1) 替換中的引用
普通捕獲組:$number
命名捕獲組:${name}
替換中應(yīng)用,仍是上面的例子。
舉例:替換掉html標(biāo)簽中的屬性。使用普通捕獲組。
string data = "<table id=\"test\"><tr class=\"light\"><td> test </td></tr></table>"; richTextBox2.Text = Regex.Replace(data, @"(?i)<([a-z]+)[^>]*>", "<$1>"); //輸出 <table><tr><td> test </td></tr></table>
使用命名捕獲組。
string data = "<table id=\"test\"><tr class=\"light\"><td> test </td></tr></table>"; richTextBox2.Text = Regex.Replace(data, @"(?i)<(?<tag>[a-z]+)[^>]*>", "<${tag}>"); //輸出 <table><tr><td> test </td></tr></table>
2) 匹配后的引用
對(duì)于匹配結(jié)果中捕獲組捕獲內(nèi)容的引用,可以通過Groups和Result對(duì)象進(jìn)行引用。
string test = "<a href=\"http://www.dbjr.com.cn\">jb51</a>"; Regex reg = new Regex(@"(?is)<a(?:(?!href=).)*href=(['""]?)(?<url>[^""'\s>]*)\1[^>]*>(?<text>(?:(?!</a>).)*)</a>"); MatchCollection mc = reg.Matches(test); foreach (Match m in mc) { ? ? ?richTextBox2.Text += "m.Value:".PadRight(25) + m.Value + "\n"; ? ? ?richTextBox2.Text += "m.Result(\"$0\"):".PadRight(25) + m.Result("$0") + "\n"; ? ? ?richTextBox2.Text += "m.Groups[0].Value:".PadRight(25) + m.Groups[0].Value + "\n"; ? ? ?richTextBox2.Text += "m.Result(\"$2\"):".PadRight(25) + m.Result("$2") + "\n"; ? ? ?richTextBox2.Text += "m.Groups[2].Value:".PadRight(25) + m.Groups[2].Value + "\n"; ? ? ?richTextBox2.Text += "m.Result(\"${url}\"):".PadRight(25) + m.Result("${url}") + "\n"; ? ? ?richTextBox2.Text += "m.Groups[\"url\"].Value:".PadRight(25) + m.Groups["url"].Value + "\n"; ? ? ?richTextBox2.Text += "m.Result(\"$3\"):".PadRight(25) + m.Result("$3") + "\n"; ? ? ?richTextBox2.Text += "m.Groups[3].Value:".PadRight(25) + m.Groups[3].Value + "\n"; ? ? ?richTextBox2.Text += "m.Result(\"${text}\"):".PadRight(25) + m.Result("${text}") + "\n"; ? ? ?richTextBox2.Text += "m.Groups[\"text\"].Value:".PadRight(25) + m.Groups["text"].Value + "\n"; } //輸出 m.Value: ? ? ? ? ? ? ? ? <a href="http://www.dbjr.com.cn">jb51</a> m.Result("$0"): ? ? ? ? ?<a href="http://www.dbjr.com.cn">jb51</a> m.Groups[0].Value: ? ? ? <a href="http://www.dbjr.com.cn">jb51</a> m.Result("$2"): ? ? ? ? ?//www.dbjr.com.cn m.Groups[2].Value: ? ? ? //www.dbjr.com.cn m.Result("${url}"): ? ? ?//www.dbjr.com.cn m.Groups["url"].Value: ? //www.dbjr.com.cn m.Result("$3"): ? ? ? ? ?jb51 m.Groups[3].Value: ? ? ? jb51 m.Result("${text}"): ? ? jb51 m.Groups["text"].Value: ?jb51
對(duì)于捕獲組0的引用,可以簡(jiǎn)寫作m.Value。
到此這篇關(guān)于正則基礎(chǔ)之 捕獲組(capture group)的文章就介紹到這了,更多相關(guān)正則捕獲組內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
PHP 正則表達(dá)式特殊字符 [:alnum:] [:alpha:] 等
正則表達(dá)式中有兩個(gè)很重要的特殊字符就是"[ ]"。他們可以匹配"[]"之中出現(xiàn)過的字符,比如"/[az]/"可以匹配單個(gè)字符"a"或者"z";如果把上面的表達(dá)式改成這樣"/[a-z]/",就可以匹配任何單個(gè)小寫字母,比如"a"、"b"等等。2011-09-09一串字字符中多個(gè)逗號(hào)替換為一個(gè) 既標(biāo)準(zhǔn)分隔符(正則表達(dá)式)
一串字字符中多個(gè)逗號(hào)轉(zhuǎn)換為一個(gè),既標(biāo)準(zhǔn)分隔符(正則表達(dá)式),借助上一篇文章正則表達(dá)式快速入門,來完成了這個(gè)轉(zhuǎn)換過程2012-11-11JavaScript中正則表達(dá)式的概念與應(yīng)用
這篇文章主要介紹了JavaScript中正則表達(dá)式的概念與應(yīng)用的相關(guān)資料,需要的朋友可以參考下2017-10-10正則表達(dá)式檢測(cè)用戶輸入的email地址是否合法
在注冊(cè)系統(tǒng)開發(fā)中,需要檢測(cè)用戶輸入的email地址是否合法,都可以使用正則表達(dá)式來檢測(cè),下面有個(gè)小例子,希望對(duì)大家有所幫助2014-01-01javascript正則表達(dá)式處理中文和中文標(biāo)點(diǎn)符號(hào)的過程
在寫項(xiàng)目時(shí)遇到需要匹配字符串中所有的漢字并且包括簡(jiǎn)單的中文標(biāo)點(diǎn)符號(hào),下面這篇文章主要給大家介紹了關(guān)于javascript正則表達(dá)式處理中文和中文標(biāo)點(diǎn)符號(hào)的相關(guān)資料,需要的朋友可以參考下2024-02-02校驗(yàn)普通電話、傳真號(hào)碼的正則表達(dá)式(可以+開頭,除數(shù)字外,可含有-)
校驗(yàn)普通電話、傳真號(hào)碼:可以“+”開頭,除數(shù)字外,可含有“-”2010-10-10