.NET正則基礎(chǔ)之.NET正則匹配模式
1、概述
匹配模式指的是一些可以改變正則表達(dá)式匹配行為的選項(xiàng)或修飾符。不同的語(yǔ)言支持的匹配模式不同,使用的方式也不同。
一般可分為全局和內(nèi)聯(lián)兩種。下面主要介紹.NET中的匹配模式,其它語(yǔ)言的匹配模式,后續(xù)視情況補(bǔ)充。
2、匹配模式
2.1全局匹配模式和內(nèi)聯(lián)匹配模式概述
.NET中的全局匹配模式是通過(guò)RegexOptions 枚舉值指定的,可以按位“或”進(jìn)行組合,全局匹配模式只能作用于整個(gè)正則表達(dá)式。全局匹配模式提供的模式更多,可以靈活的動(dòng)態(tài)指定匹配模式。
而內(nèi)聯(lián)匹配模式是通過(guò)在正則表達(dá)式中,使用(?imnsx-imnsx:)或(?imnsx-imnsx)的分組構(gòu)造來(lái)改變正則表達(dá)式的匹配行為的。內(nèi)聯(lián)匹配模式更靈活、簡(jiǎn)潔,但是提供的模式較少。
下表摘自MSDN,部分說(shuō)明做了修改。
RegexOption 成員 | 內(nèi)聯(lián)字符 | 說(shuō)明 |
None | N/A | 指定不設(shè)置任何選項(xiàng)。 |
IgnoreCase | i | 指定不區(qū)分大小寫的匹配。 |
Multiline | m | 指定多行模式。更改 ^ 和 $ 的含義,以使它們分別與任何行的開(kāi)頭和結(jié)尾匹配,而不只是與整個(gè)字符串的開(kāi)頭和結(jié)尾匹配。 |
ExplicitCapture | n | 指定唯一有效的捕獲是顯式命名或編號(hào)的 (?<name>…) 形式的組。這允許圓括號(hào)充當(dāng)非捕獲組,從而避免了由 (?:…) 導(dǎo)致的語(yǔ)法上的笨拙。 |
Compiled | N/A | 指定正則表達(dá)式將被編譯為程序集。生成該正則表達(dá)式的 Microsoft 中間語(yǔ)言 (MSIL) 代碼;以較長(zhǎng)的啟動(dòng)時(shí)間為代價(jià),得到更快的執(zhí)行速度。 |
Singleline | s | 指定單行模式。更改句點(diǎn)字符 (.) 的含義,以使它與每個(gè)字符(而不是除 \n 之外的所有字符)匹配。 |
IgnorePatternWhitespace | x | 指定從模式中排除非轉(zhuǎn)義空白并啟用數(shù)字符號(hào) (#) 后面的注釋。請(qǐng)注意,空白永遠(yuǎn)不會(huì)從字符類中消除。 |
RightToLeft | N/A | 指定搜索是從右向左而不是從左向右進(jìn)行的。具有此選項(xiàng)的正則表達(dá)式將移動(dòng)到起始位置的左邊而不是右邊。 |
ECMAScript | N/A | 指定已為表達(dá)式啟用了符合 ECMAScript 的行為。此選項(xiàng)僅可與 IgnoreCase 和 Multiline 標(biāo)志一起使用。將 ECMAScript 同任何其他標(biāo)志一起使用將導(dǎo)致異常。 |
CultureInvariant | N/A | 指定忽略語(yǔ)言中的區(qū)域性差異。 |
2.2全局匹配模式
下面根據(jù)各種模式使用的頻率進(jìn)行講解。
2.2.1 IgnoreCase 忽略大小寫
幾乎所有支持正則的語(yǔ)言中都提供了這一模式,是應(yīng)用最多的模式之一,同時(shí)也是被“濫”用最多的模式之一。
開(kāi)啟忽略大小寫模式,則字符可以同時(shí)匹配大寫或小寫形式。比如在此模式下,正則表達(dá)式“<br>”可同時(shí)匹配“<br>”和“<BR>”
但并不是所有的字符都有大小寫形式,所以在書寫的正則中,如果不存在可區(qū)分大小寫形式的元字符或是字符序列時(shí),開(kāi)啟這一模式是沒(méi)有任何意義的。
比如替換一般的html標(biāo)簽的正則表達(dá)式
string result = Regex.Replace(srcStr, @"<[^>]*>", "", RegexOptions.IgnoreCase);
因?yàn)?lt;[^>]*>沒(méi)有哪一個(gè)元字符或是字符序列具有大小寫形式,所以這里的RegexOptions.IgnoreCase是多余的,用在這里雖然不會(huì)改變匹配結(jié)果,但是會(huì)降低匹配效率,同時(shí)這也不是一個(gè)好的習(xí)慣。
只有在正則表達(dá)式中,注意是正則表達(dá)式中,而不是待匹配的源字符串中,涉及到大小寫形式的元字符或是字符序列時(shí),才使用IgnoreCase模式。
2.2.2 Multiline 多行模式
多行模式改變的是“^”和“$”的匹配行為,使“^”和“$”不僅可以匹配整個(gè)字符串的開(kāi)始和結(jié)束位置,還可以匹配每行的開(kāi)始和結(jié)束位置。
首先說(shuō)明一下“行”的范圍。雖然我們?cè)诔绦蛑辛?xí)慣用“\r\n”來(lái)表示換行,但實(shí)際上“\r”和“\n”是不相關(guān)的兩個(gè)字符,一個(gè)表示回車,一個(gè)表示換行。由于歷史原因,“\r”并不是所有系統(tǒng)都支持的,所以“行”是由“\n”來(lái)分割的,其中“\n”屬于前一“行”,而不屬于后一“行”。
舉例來(lái)說(shuō),字符串“a\r\nbc\r\n”共有三行,“a\r\n”為一行,“bc\r\n”為一行,最后還有一個(gè)“”空行。
2.2.2.1 在不開(kāi)啟多行模式情況下,“^”和“$”匹配范圍
“^”的匹配范圍
MatchCollection?mc =?Regex.Matches("a\r\nbc\r\n",?@"^"); foreach?(Match?m?in?mc) { ?????richTextBox2.Text +=?"匹配內(nèi)容:"?+ m.Value +?"??匹配開(kāi)始索引:"?+ m.Index +?"??匹配長(zhǎng)度:"?+ m.Length +?"\n"; } /*--------輸出-------- 匹配內(nèi)容:??匹配開(kāi)始索引:0??匹配長(zhǎng)度:0 */
“$”的匹配范圍
MatchCollection?mc =?Regex.Matches("a\r\nbc\r\n",?@"$"); foreach?(Match?m?in?mc) { ?????richTextBox2.Text +=?"匹配內(nèi)容:"?+ m.Value +?"??匹配開(kāi)始索引:"?+ m.Index +?"??匹配長(zhǎng)度:"?+ m.Length +?"\n"; } /*--------輸出-------- 匹配內(nèi)容:??匹配開(kāi)始索引:6??匹配長(zhǎng)度:0 匹配內(nèi)容:??匹配開(kāi)始索引:7??匹配長(zhǎng)度:0 */
注意:這里需要注意的是,在沒(méi)有開(kāi)啟多行模式時(shí),字符串結(jié)尾如果是“\n”,那么“$”是可以匹配兩個(gè)位置的,一個(gè)是“\n”前的位置,一個(gè)是字符串結(jié)束位置。字符串結(jié)尾如果不是“\n”,那么“$”就只匹配字符串結(jié)束位置。
MatchCollection?mc =?Regex.Matches("a\r\nbc\r",?@"$"); foreach?(Match?m?in?mc) { ?????richTextBox2.Text +=?"匹配內(nèi)容:"?+ m.Value +?"??匹配開(kāi)始索引:"?+ m.Index +?"??匹配長(zhǎng)度:"?+ m.Length +?"\n"; } /*--------輸出-------- 匹配內(nèi)容:??匹配開(kāi)始索引:6??匹配長(zhǎng)度:0 */
2.2.2.2 在開(kāi)啟了多行模式后,“^”和“$”匹配范圍
“^”的匹配范圍
MatchCollection?mc =?Regex.Matches("a\r\nbc\r\n",?@"^",?RegexOptions.Multiline); foreach?(Match?m?in?mc) { ?????richTextBox2.Text +=?"匹配內(nèi)容:"?+ m.Value +?"??匹配開(kāi)始索引:"?+ m.Index +?"??匹配長(zhǎng)度:"?+ m.Length +?"\n"; } /*--------輸出-------- 匹配內(nèi)容:??匹配開(kāi)始索引:0??匹配長(zhǎng)度:0 匹配內(nèi)容:??匹配開(kāi)始索引:3??匹配長(zhǎng)度:0 匹配內(nèi)容:??匹配開(kāi)始索引:7??匹配長(zhǎng)度:0 */
“$”的匹配范圍
MatchCollection?mc =?Regex.Matches("a\r\nbc\r\n",?@"$",?RegexOptions.Multiline); foreach?(Match?m?in?mc) { ?????richTextBox2.Text +=?"匹配內(nèi)容:"?+ m.Value +?"??匹配開(kāi)始索引:"?+ m.Index +?"??匹配長(zhǎng)度:"?+ m.Length +?"\n"; } /*--------輸出-------- 匹配內(nèi)容:??匹配開(kāi)始索引:2??匹配長(zhǎng)度:0 匹配內(nèi)容:??匹配開(kāi)始索引:6??匹配長(zhǎng)度:0 匹配內(nèi)容:??匹配開(kāi)始索引:7??匹配長(zhǎng)度:0 */
2.2.2.3 匹配結(jié)果分析
“^”匹配結(jié)果分析
在不開(kāi)啟多行模式時(shí),“^”只匹配字符串的開(kāi)始位置,也就是位置0。
在開(kāi)啟了多行模式后,“^”匹配字符串開(kāi)始位置和每個(gè)“\n”之后的行起始位置。
“$”匹配結(jié)果分析
在不開(kāi)啟多行模式時(shí),如果字符結(jié)尾是“\n”,那么“$”會(huì)匹配結(jié)尾“\n”之前和結(jié)束兩個(gè)位置。
在開(kāi)啟多行模式后,“$”匹配每行“\n”之前的位置和字符串結(jié)束位置。
需要注意的是,在.NET中,無(wú)論是否開(kāi)啟多行模式,“^”和“$”匹配的都只是一個(gè)位置,是零寬度的。其它語(yǔ)言中“^”和“$”的意義可能會(huì)有所不同。
只有在正則表達(dá)式中涉及到多行的“^”和“$”的匹配時(shí),才使用Multiline模式。
2.2.2.4 應(yīng)用舉例
典型應(yīng)用一(參考 正則中加字符的問(wèn)題):
需求描述:
fffffffffff
fffffffffff
dfdfdfdf
erererere
ferewfdfds
每行后面加一個(gè)“ttt”,即為
fffffffffffttt
fffffffffffttt
dfdfdfdfttt
ererererettt
ferewfdfdsttt
代碼實(shí)現(xiàn):
string result = Regex.Replace(yourStr, @"^.*$", "$0ttt", RegexOptions.Multiline);
典型應(yīng)用二
需求描述:
源字符串
CODE39/CODE93:
A-Z
space,-,.,$,/,+,%
CODE128A:
A-Z
0-9
space,!,",#,$,%,&,…,(,)*,+,逗號(hào),-,.,/, <,=,>,?,@,[,],^,_
CODE128B:
A-Z
a-z
0-9
space,!,",#,$,%,&,…,(,)*,+,逗號(hào),-,.,/, <,=,>,?,@,[,],^,_,{,},|,~
CODE2of5:
0-9
說(shuō)明:
CODE128A:->條碼類別
A-Z
0-9
space,!,",#,$,%,&,…,(,)*,+,逗號(hào),-,.,/, <,=,>,?,@,[,],^,_->表示范圍
要求分別匹配出條碼類別和表示范圍
代碼實(shí)現(xiàn):
MatchCollection?mc =?Regex.Matches(yourStr,?@"(?<type>[^\n:]+):\s*(?<range>(^(?!\s*$).*$\n?)*)",?RegexOptions.Multiline); foreach?(Match?m?in?mc) { ?????richTextBox2.Text +=?"條碼類別:?\n"?+ m.Groups["type"].Value +?"\n"; ?????richTextBox2.Text +=?"表示范圍:?\n"?+ m.Groups["range"].Value +?"\n"; } /*--------輸出-------- 條碼類別: CODE39/CODE93 表示范圍: A-Z space,-,.,$,/,+,% 條碼類別: CODE128A 表示范圍: A-Z 0-9 space,!,",#,$,%,&,…,(,)*,+,逗號(hào),-,.,/, <,=,>,?,@,[,],^,_ 條碼類別: CODE128B 表示范圍: A-Z a-z 0-9 space,!,",#,$,%,&,…,(,)*,+,逗號(hào),-,.,/, <,=,>,?,@,[,],^,_,{,},|,~ 條碼類別: CODE2of5 表示范圍: 0-9 */
2.2.3 Singleline 單行模式
單行模式改變的是小數(shù)點(diǎn)“.”的匹配行為,使小數(shù)點(diǎn)可以匹配包含換行符“\n”在內(nèi)的任意一個(gè)字符。
這是一個(gè)很不幸的命名,總讓人誤會(huì)它與Multiline多行模式是有關(guān)聯(lián)的,而事實(shí)上它改變的是小數(shù)點(diǎn)的匹配行為,與Multiline多行模式?jīng)]有任何關(guān)聯(lián),由于歷史原因,這一不幸的命名被保留了下來(lái)。使用時(shí)需要注意。
單行模式通常在匹配有換行的文本時(shí)使用,采用小數(shù)點(diǎn)+單行模式的方式匹配任意字符,在.NET中是效率最高的。參考 正則基礎(chǔ)之——小數(shù)點(diǎn)。
典型應(yīng)用:
源字符串:
<a>There is one obvious advantage:</a> <div> ????<p> ????????You've seen it coming!<br/> ????????Buy now and get nothing for free!<br/> ????????Well, at least no free beer. Perhaps a bear,<br/> ????????if you can afford it. ????</p> </div> <a>Now that you've got...</a> <div> ????<p> ????????your bear, you have to admit it!<br/> ????????No, we aren't selling bears. ????</p> </div>
需求:取<div>標(biāo)簽之間的內(nèi)容
代碼實(shí)現(xiàn):
MatchCollection?mc =?Regex.Matches(yourStr,?@"<div[^>]*>(?:(?!</div\b).)*</div>",?RegexOptions.Singleline|RegexOptions.IgnoreCase); foreach?(Match?m?in?mc) { ?????richTextBox2.Text += m.Value +?"\n-------------------\n"; } /*--------輸出-------- <div> ????<p> ????????You've seen it coming!<br/> ????????Buy now and get nothing for free!<br/> ????????Well, at least no free beer. Perhaps a bear,<br/> ????????if you can afford it. ????</p> </div> ------------------- <div> ????<p> ????????your bear, you have to admit it!<br/> ????????No, we aren't selling bears. ????</p> </div> ------------------- */
2.2.4 Compiled 編譯模式
Compiled改變的是.NET中正則表達(dá)式的編譯方式。啟用了Compiled模式,會(huì)延長(zhǎng)啟動(dòng)時(shí)間,占用更多的內(nèi)存,會(huì)提高匹配速度。當(dāng)然,對(duì)最終性能的影響,需要根據(jù)具體問(wèn)題綜合考慮的。這一模式也是被“濫”用最多的模式之一。
程序運(yùn)行過(guò)程中,第一次遇到正則表達(dá)式,需要加載正則引擎,對(duì)正則表達(dá)式進(jìn)行必要的語(yǔ)法檢查,并做適當(dāng)?shù)膬?yōu)化,最后把它轉(zhuǎn)換為適合正則引擎應(yīng)用的形式。這種“解析”過(guò)程,對(duì)于復(fù)雜的正則表達(dá)式,頻繁調(diào)用或是匹配較大的數(shù)據(jù)源時(shí),對(duì)效率的影響較大。
這時(shí)可以在構(gòu)建正則表達(dá)式時(shí)開(kāi)啟Compiled模式。這樣做會(huì)將正則表達(dá)式直接編譯為MSIL代碼,在正則匹配過(guò)程中,可以由JIT優(yōu)化為更快的本地機(jī)器代碼,獲得更高的匹配速度。但這種方式會(huì)降低正則的解析速度,占用更多的內(nèi)存,而且它占用的內(nèi)存在程序運(yùn)行過(guò)程中會(huì)一直占用,無(wú)法釋放。
什么場(chǎng)景下使用Compiled模式,需要根據(jù)實(shí)際情況具體問(wèn)題具體分析,一般來(lái)說(shuō),以下場(chǎng)景不適合使用Compiled模式:
1. 對(duì)匹配效率沒(méi)有要求的場(chǎng)景;
2. 非常簡(jiǎn)單的正則表達(dá)式;
3. 極少調(diào)用的方法中聲明的正則表達(dá)式;
4. 循環(huán)體中聲明的正則表達(dá)式(除了動(dòng)態(tài)生成的正則表達(dá)式,否則不要在循環(huán)體內(nèi)聲明正則表達(dá)式);
5. 靜態(tài)方法中聲明的正則表達(dá)式(靜態(tài)方法每次調(diào)用都需要重新編輯正則表達(dá)式,使用Compiled模式只會(huì)降低效率)。
2.2.5 RightToLeft 從右到左模式
RightToLeft改變的是正則表達(dá)式匹配的順序,從右到左進(jìn)行匹配。目前只有.NET支持這一模式,但它對(duì)這一模式的支持并不是很完善,有時(shí)容易讓人費(fèi)解,所以除非對(duì)源字符串的構(gòu)成很了解,而且又不得不使用的情況,否則不要輕易使用這一模式。
典型應(yīng)用(參考 求一個(gè)好的算法):
一個(gè)由字母組成的字符串,最長(zhǎng)14位,要求每隔2位加一個(gè)逗號(hào),最左邊不加,求一個(gè)好的算法
例:“abcdefg” 返回“a,bc,de,fg”
代碼實(shí)現(xiàn):
string?test =?"abcdefg"; string?result =?Regex.Replace(yourStr,?@"(?<!^)[a-zA-Z]{2}",?",$0",?RegexOptions.RightToLeft);
2.2.6 None
這一模式指定不開(kāi)啟任何模式。在.NET中RegexOptions 枚舉值是按位“或”組合,None模式我目前只找到一種應(yīng)用場(chǎng)景,就是在動(dòng)態(tài)生成正則表達(dá)式時(shí),動(dòng)態(tài)指定模式時(shí)使用。
///?<summary> ///?動(dòng)態(tài)生成正則參數(shù)列表 ///?</summary> ///?<returns></returns> private?RegexOptions?getParameter() { ????RegexOptions?roList =?RegexOptions.None; ????if?(cbIgnoreCase.Checked) ????{ ?????????roList = roList |?RegexOptions.IgnoreCase; ?????} ?????if?(cbSingleline.Checked) ?????{ ??????????roList = roList |?RegexOptions.Singleline; ?????} ?????if?(cbMultiline.Checked) ?????{ ??????????roList = roList |?RegexOptions.Multiline; ?????} ?????if?(cbCompiled.Checked) ?????{ ??????????roList = roList |?RegexOptions.Compiled; ?????} ?????if?(cbRightToLelft.Checked) ?????{ ??????????roList = roList |?RegexOptions.RightToLeft; ?????} ?????return?roList; }
2.2.7 ExplicitCapture
這一模式改變的是普通捕獲組的匹配行為。將普通捕獲組解釋為非捕獲組,只有顯式命名的命名捕獲組才當(dāng)作捕獲組使用。
捕獲組的作用是將括號(hào)()內(nèi)子表達(dá)式匹配到的內(nèi)容保存到內(nèi)存中一個(gè)組里,供以后引用,在.NET中捕獲組有兩種形式
(Expression) 普通捕獲組
(?<name>Expression) 命名捕獲組
其它形式的(?...)都不是捕獲組。
但是(Expression)這種捕獲組語(yǔ)法規(guī)則也帶來(lái)一個(gè)副作用,在一些不得不使用()的場(chǎng)合,會(huì)默認(rèn)為使用了捕獲組,將匹配到的內(nèi)容保存到內(nèi)存中,而有些情況下這些內(nèi)容并不需要關(guān)心的,浪費(fèi)了系統(tǒng)資源,降低了匹配效率,所以才有了非捕獲組(?:Expression)的出現(xiàn),來(lái)抵消這一副作用。而非捕獲組帶來(lái)的另一個(gè)副作用的就是可讀性的降低。
ExplicitCapture模式是為了在不犧牲匹配效率的前提下,提高正則表達(dá)式的可讀性,一般在命名捕獲組和普通捕獲組混合出現(xiàn),而又不關(guān)心普通捕獲組的正則表達(dá)式中使用,如取鏈接和文字的正則表達(dá)式中
MatchCollection?mc =?Regex.Matches(yourStr,?@"(?is)<a((?!href=).)*href=(?<s>['""]?)(?<url>[^""'\s>]*)\k<s>[^>]*>(?<text>((?!</a>).)*)</a>",?RegexOptions.ExplicitCapture); foreach?(Match?m?in?mc) { ??????richTextBox2.Text += m.Groups["url"].Value +?"\n"; ?????richTextBox2.Text += m.Groups["text"].Value +?"\n"; }
開(kāi)啟ExplicitCapture模式對(duì)正則表達(dá)式解釋行為的影響,可以參考如下舉例,匹配時(shí)間的正則表達(dá)式
未開(kāi)啟ExplicitCapture模式
string?test =?"<li title=\"截至2009-07-28 20:45:49,用戶的總技術(shù)分為:5988;截至2009-07-26日,用戶的總技術(shù)分排名為:4133\">(...)</li>"; Regex?reg =?new?Regex(@"([01][0-9]|2[0-3])(:[0-5][0-9]){2}"); MatchCollection?mc = reg.Matches(test); foreach?(Match?m?in?mc) { ?????richTextBox2.Text += m.Value +?"\n"; ?????richTextBox2.Text += m.Groups[1].Value +?"\n"; ?????richTextBox2.Text += m.Groups[2].Value +?"\n"; } /*--------輸出-------- 20:45:49 20 :49 */
開(kāi)啟ExplicitCapture模式
string?test =?"<li title=\"截至2009-07-28 20:45:49,用戶的總技術(shù)分為:5988;截至2009-07-26日,用戶的總技術(shù)分排名為:4133\">(...)</li>"; Regex?reg =?new?Regex(@"([01][0-9]|2[0-3])(:[0-5][0-9]){2}"); MatchCollection?mc = reg.Matches(test); foreach?(Match?m?in?mc) { ?????richTextBox2.Text += m.Value +?"\n"; ?????richTextBox2.Text += m.Groups[1].Value +?"\n"; ?????richTextBox2.Text += m.Groups[2].Value +?"\n"; } /*--------輸出-------- 20:45:49 */
一般來(lái)說(shuō),關(guān)心的只是整個(gè)正則表達(dá)式匹配的整體,啟用了ExplicitCapture模式后,“([01][0-9]|2[0-3])”和“(:[0-5][0-9])”將不會(huì)被解釋為捕獲組,匹配到的內(nèi)容也不會(huì)保存到內(nèi)存中。
開(kāi)啟ExplicitCapture模式雖然可以提高正則表達(dá)式的可讀性,但ExplicitCapture這一模式本身容易被人忽略,所以這種模式應(yīng)用得也比較少。
一旦使用了ExplicitCapture模式,要注意的是,除非你清楚捕獲組的編號(hào)規(guī)則,否則盡量不要再使用\number方式進(jìn)行反向引用,可以使用\k<name>方式進(jìn)行反向引用。
Regex?reg =?new?Regex(@"href=(['""]?)(?<url>[^'""\s>]+)\1",?RegexOptions.ExplicitCapture); MatchCollection?mc = reg.Matches(yourStr); foreach?(Match?m?in?mc) { ?????richTextBox2.Text += m.Value +?"\n"; }
以上匹配鏈接的代碼通常是得不到任何結(jié)果的,因?yàn)檫@里“\1”引用的內(nèi)容,不再是“(['""]?)”匹配到的內(nèi)容,而是“(?<url>[^'""\s>]+)”匹配到的內(nèi)容,等價(jià)于“(?<url>[^'""\s>]+)\k<url>”,而這樣的字符串,通常是不存在的。
2.2.8 IgnorePatternWhitespace
這一模式忽略正則表達(dá)式中的非轉(zhuǎn)義空白字符,并啟用“#”后面的注釋,通常用于增強(qiáng)正則表達(dá)式的可讀性或是用于教學(xué)目的。
舉個(gè)例子基本上就會(huì)明白了
string?test =?"(One) and ( Two (Three) Four)."; Regex?reg =?new?Regex(@"\(??????????????????????????#普通開(kāi)括弧 ??????????????????????????(?>???????????????????????#固化分組 ?????????????????????????????\(???(?<OPEN>)?????????#遇到開(kāi)括弧'OPEN'計(jì)數(shù)加1 ????????????????????????????|???????????????????????#分支結(jié)構(gòu) ?????????????????????????????\)???(?<-OPEN>)????????#遇到閉括弧'OPEN'計(jì)數(shù)減1 ????????????????????????????|???????????????????????#分支結(jié)構(gòu) ?????????????????????????????[^()]+?????????????????#非括弧的其它任意字符 ??????????????????????????)*????????????????????????#以上子串出現(xiàn)0次或任意多次 ??????????????????????????(?(OPEN)(?!))?????????????#判斷是否還有'OPEN',有則說(shuō)明不配對(duì),什么都不匹配 ????????????????????????\)??????????????????????????#普通閉括弧 ???????????????????????",?RegexOptions.IgnorePatternWhitespace); MatchCollection?mc = reg.Matches(test); foreach?(Match?m?in?mc) { ??????richTextBox2.Text += m.Value +?"\n"; }
其中的空白字符被忽略,“#”及該行后面的內(nèi)容被解釋為注釋。
2.2.9 ECMAScript
這一模式將按ECMA的JavaScript語(yǔ)義來(lái)解析正則表達(dá)式。通常影響的是以下元字符的匹配行為
\w、\W、\d、\D、\s、\S
使得以上元字符只能匹配ASCII碼字符,而不再是匹配相應(yīng)的Unicode字符。
事實(shí)上比如需求中明確要求只匹配英文字母,數(shù)字,下劃線,而不包含漢字等字符,那么完全可以用“[A-Za-z0-9_]”,而不使用“\w”,雖然不夠簡(jiǎn)潔,但可讀性更好,語(yǔ)義更明確。
這一模式在.NET中的應(yīng)用比較少,如不清楚什么場(chǎng)景下應(yīng)該使用,可以忽略這一模式。
2.2.10 CultureInvariant
這一模式指定忽略語(yǔ)言中的區(qū)域性差異。一般與IgnoreCase模式一起使用,這一模式的應(yīng)用場(chǎng)景很少,一般可以忽略,無(wú)需了解。
2.3 內(nèi)聯(lián)匹配模式
內(nèi)聯(lián)匹配模式在正則表達(dá)式內(nèi)部使用,可以改變局部子表達(dá)式的匹配行為,內(nèi)聯(lián)匹配模式支持的模式較少,僅有immsx五種,但使用起來(lái)更簡(jiǎn)潔,更靈活。在.NET中支持(?imnsx-imnsx:)和(?imnsx-imnsx)兩種形式。
各內(nèi)聯(lián)匹配模式對(duì)應(yīng)的全局匹配模式見(jiàn)匹配模式列表。以下僅就(?i)忽略大小寫模式進(jìn)行講解,其它模式類同。
2.3.1 (?imnsx-imnsx:)形式
語(yǔ)法:(?i:Expression)
這種語(yǔ)法規(guī)則表達(dá)為括號(hào)內(nèi)的子表達(dá)式開(kāi)啟忽略大小寫模式。
舉例:^[A-Z](?i:[A-Z]{9,19})$
以上正則表示,首字符必須為大寫字母,后面跟9到19個(gè)大小寫字母。
string[] test =?new?string[] {?"Abc",?"AbcdefGHIjklmn",?"abcdefghijklmn"?}; Regex?reg =?new?Regex(@"^[A-Z](?i:[A-Z]{9,19})$"); foreach?(string?s?in?test) { ?????richTextBox2.Text +=?"源字符串:?"?+ s.PadRight(15,?' ') +?"??匹配結(jié)果:?"?+ reg.IsMatch(s) +?"\n"; } /*--------輸出-------- 源字符串:?Abc??????????????匹配結(jié)果:?False 源字符串:?AbcdefGHIjklmn???匹配結(jié)果:?True 源字符串:?abcdefghijklmn???匹配結(jié)果:?False */
語(yǔ)法:(?-i:Expression)
這種語(yǔ)法規(guī)則表達(dá)為括號(hào)內(nèi)的子表達(dá)式關(guān)閉忽略大小寫模式。通常與全局匹配模式配合使用,表示全局為忽略大小寫的,局部為嚴(yán)格區(qū)分大小寫。
舉例:<div id="(?-i:TEST)" [^>]*>[\w\s]+</div>
以上正則表示,div標(biāo)簽中,僅匹配id為全大寫的“TEST”的標(biāo)簽內(nèi)容,其余標(biāo)簽不匹配。
string?test =?"<DIV id=\"Test\" class=\"create\">first</div> and <DIV id=\"TEST\" class=\"delete\">second</div>"; Regex?reg =?new?Regex(@"<div id=""(?-i:TEST)""[^>]*>[\w\s]+</div>",?RegexOptions.IgnoreCase); MatchCollection?mc = reg.Matches(test); foreach(Match?m?in?mc) { ??????richTextBox2.Text += m.Value +?"\n"; } /*--------輸出-------- <DIV id="TEST" class="delete">second</div> */
2.3.2 (?imnsx-imnsx)
語(yǔ)法:(?i) 或 (?-i)
(?i)為所在位置右側(cè)的子表達(dá)式開(kāi)啟忽略大小寫模式,直到出現(xiàn)(?-i)或者到表達(dá)式結(jié)束為止;(?-i)為所在位置右側(cè)的子表達(dá)式關(guān)閉忽略大小寫模式,直到出現(xiàn)(?i)或者到表達(dá)式結(jié)束為止。
通常在正則表達(dá)式開(kāi)始位置使用(?i)來(lái)代替RegexOptions.IgnoreCase,使代碼更簡(jiǎn)潔。如提取鏈接和文字的正則表達(dá)式
MatchCollection?mc =?Regex.Matches(yourStr,?@"(?is)<a(?:(?!href=).)*href=(['""]?)(?<url>[^""'\s>]*)\1[^>]*>(?<text>(?:(?!</a>).)*)</a>"); foreach?(Match?m?in?mc) { ??????richTextBox2.Text += m.Groups["url"].Value +?"\n"; ??????richTextBox2.Text += m.Groups["text"].Value +?"\n"; }
3、小結(jié)
.NET中的正則匹配模式基本上已講解完了,最后再來(lái)總結(jié)一下各匹配模式的應(yīng)用場(chǎng)景吧。
RegexOption 成員 | 內(nèi)聯(lián)字符 | 作用/應(yīng)用場(chǎng)景 |
None | N/A | 指定不設(shè)置任何選項(xiàng)。 一般在動(dòng)態(tài)指定匹配模式時(shí)使用。 |
IgnoreCase | i | 指定不區(qū)分大小寫的匹配。 只有在正則表達(dá)式中,注意是正則表達(dá)式中,而不是待匹配的源字符串中,涉及到大小寫形式的元字符或是字符序列時(shí),才使用IgnoreCase模式。 |
Multiline | m | 指定多行模式。更改 ^ 和 $ 的含義,以使它們分別與任何行的開(kāi)頭和結(jié)尾匹配,而不只是與整個(gè)字符串的開(kāi)頭和結(jié)尾匹配。 只有在正則表達(dá)式中涉及到多行的“^”和“$”的匹配時(shí),才使用Multiline模式。 |
ExplicitCapture | n | 指定唯一有效的捕獲是顯式命名或編號(hào)的 (?<name>…) 形式的組。這允許圓括號(hào)充當(dāng)非捕獲組,從而避免了由 (?:…) 導(dǎo)致的語(yǔ)法上的笨拙。 ExplicitCapture模式是為了在不犧牲匹配效率的前提下,提高正則表達(dá)式的可讀性,一般在命名捕獲組和普通捕獲組混合出現(xiàn),而又不關(guān)心普通捕獲組的正則表達(dá)式中使用。 |
Compiled | N/A | 指定正則表達(dá)式將被編譯為程序集。生成該正則表達(dá)式的 Microsoft 中間語(yǔ)言 (MSIL) 代碼;以較長(zhǎng)的啟動(dòng)時(shí)間為代價(jià),得到更快的執(zhí)行速度。 以下場(chǎng)景不適合使用: 1. 對(duì)匹配效率沒(méi)有要求的場(chǎng)景; 2. 非常簡(jiǎn)單的正則表達(dá)式; 3. 極少調(diào)用的方法中聲明的正則表達(dá)式; 4. 循環(huán)體中聲明的正則表達(dá)式(除了動(dòng)態(tài)生成的正則表達(dá)式,否則不要在循環(huán)體內(nèi)聲明正則表達(dá)式); 5. 靜態(tài)方法中聲明的正則表達(dá)式(靜態(tài)方法每次調(diào)用都需要重新編輯正則表達(dá)式,使用Compiled模式只會(huì)降低效率)。 |
Singleline | s | 指定單行模式。更改句點(diǎn)字符 (.) 的含義,以使它與每個(gè)字符(而不是除 \n 之外的所有字符)匹配。 單行模式通常在匹配有換行的文本時(shí)使用,采用小數(shù)點(diǎn)+單行模式的方式匹配任意字符,在.NET中是效率最高的。 |
IgnorePatternWhitespace | x | 指定從模式中排除非轉(zhuǎn)義空白并啟用數(shù)字符號(hào) (#) 后面的注釋。請(qǐng)注意,空白永遠(yuǎn)不會(huì)從字符類中消除。 為了提高可讀性,或是為正則表達(dá)式加注釋時(shí)使用。 |
RightToLeft | N/A | 指定搜索是從右向左而不是從左向右進(jìn)行的。具有此選項(xiàng)的正則表達(dá)式將移動(dòng)到起始位置的左邊而不是右邊。 除非對(duì)源字符串的構(gòu)成很了解,而且又不得不使用的情況,否則不要輕易使用這一模式。 |
ECMAScript | N/A | 指定已為表達(dá)式啟用了符合 ECMAScript 的行為。此選項(xiàng)僅可與 IgnoreCase 和 Multiline 標(biāo)志一起使用。將 ECMAScript 同任何其他標(biāo)志一起使用將導(dǎo)致異常。 除非對(duì)這一模式應(yīng)用場(chǎng)景很了解,否則不要使用。 |
CultureInvariant | N/A | 指定忽略語(yǔ)言中的區(qū)域性差異。 很少使用,一般無(wú)需了解。 |
到此這篇關(guān)于.NET正則基礎(chǔ)之.NET正則匹配模式的文章就介紹到這了,更多相關(guān).NET正則匹配模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java用正則對(duì)字符串進(jìn)行處理并判斷是否能轉(zhuǎn)為數(shù)字
這篇文章主要介紹了Java用正則對(duì)字符串進(jìn)行處理并判斷是否能轉(zhuǎn)為數(shù)字的實(shí)例代碼,代碼很簡(jiǎn)單,需要的朋友可以參考下2018-06-06Java?正則獲取兩個(gè)字母之間的內(nèi)容(最新推薦)
這篇文章主要介紹了Java正則獲取兩個(gè)字母之間的內(nèi)容,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07使用正則表達(dá)式驗(yàn)證登錄頁(yè)面輸入是否符合要求
這篇文章主要介紹了使用正則表達(dá)式驗(yàn)證登錄頁(yè)面輸入是否符合要求的實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-09-09只能是字母或數(shù)字或者是字母和數(shù)字的組合的正則previousSibling
只能是字母或數(shù)字或者是字母和數(shù)字的組合的正則previousSibling...2007-03-03