[.net 面向對象程序設計進階] (3) 正則表達式 (二) 高級應用

[.net 面向對象程序設計進階] (2) 正則表達式 ()  高級應用html

   上一節咱們說到了C#使用正則表達式的幾種方法(Replace,Match,Matches,IsMatch,Split等),還有正則表達式的幾種元字符及其應用實例,這些都是學習正則表達式的基礎。本節,咱們繼續深刻學習表達式的幾種複雜的用法。正則表達式

 1.分組 express

用小括號來指定子表達式(也叫作分組) 編程

咱們經過前一節的學習,知道了重複單個字符,只須要在字符後面加上限定符就能夠了, app

好比 a{5},若是要重複多個字符,就要使用小括號分組,而後在後面加上限定符,下面咱們看一個示例。 ide

示例一:重複單字符 和 重複分組字符學習

//示例:重複單字符 和 重複分組字符
//重複 單個字符
Console.WriteLine("請輸入一個任意字符串,測試分組:");
string inputStr = Console.ReadLine();
string strGroup1 = @"a{2}";
Console.WriteLine("單字符重複2兩次替換爲22,結果爲:"+Regex.Replace(inputStr, strGroup1,"22"));
//重複 多個字符 使用(abcd){n}進行分組限定
string strGroup2 = @"(ab\w{2}){2}";
Console.WriteLine("分組字符重複2兩次替換爲5555,結果爲:" + Regex.Replace(inputStr, strGroup2, "5555"));

運行結果以下:測試

示例二:校驗IP4地址(如:192.168.1.4,爲四段,每段最多三位,每段最大數字爲255,而且第一位不能爲0 ui

//示例:校驗IP4地址(如:192.168.1.4,爲四段,每段最多三位,每段最大數字爲255,而且第一位不能爲0)
string regexStrIp4 = @"^(((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?))$";
Console.WriteLine("請輸入一個IP4地址:");
string inputStrIp4 = Console.ReadLine();
Console.WriteLine(inputStrIp4 + " 是否爲合法的IP4地址:" + Regex.IsMatch(inputStrIp4, regexStrIp4));
Console.WriteLine("請輸入一個IP4地址:");
string inputStrIp4Second = Console.ReadLine();           
Console.WriteLine(inputStrIp4 + " 是否爲合法的IP4地址:" + Regex.IsMatch(inputStrIp4Second, regexStrIp4));

 運行結果以下:spa

在這個正則表達式中,咱們須要理解 2[0-4]\d|25[0-5]|[01]?\d\d?

這部分表示一個三位數的三種形式

2[0-4]\d     表示:2開頭+0~4的一位數字+任意數

25[0-5]      表示:25開頭+0~5的一位數字

[01]?\d\d?  表示:0或1或空  +  一位任意數字  +  一位任意數或空

這三種形式使用|分開,表示擇一種匹配

理解了這段,總體就理解了,前半部分爲 重複三次帶.號,後面一個不帶.號

^ 和 $ 表示匹配總體的開始和結束

2. 後向引用

在這節以前,仍是比較好理解的,這段有點難以理解了,可是咱們還得拍拍腦殼繼續學習。

先不說後向引用是啥,咱們先說,後向引用能幹啥?

前面咱們說了分組的概念,就是在正則表達式中使用小括號()完成分組,後向引用就是針對分組的。

若是前面分組之後,後面還要檢索前面分組內一樣的內容,就用到了後向引用,意思就是後面引用前面的分組之意。

…………………………………………………………………容我喘口氣…………………………………………………………………………………………

那麼要如何在後面引用前面分組呢?

這裏就須要有一個組名,即定義一個組名,在後面引用。

在定義組名前,說一下

則對於分組的工做原理:

A.分組後,正則會自動爲每一個分組編一個組號

B.分配組號時,從左往右掃描兩遍,第一遍給未命名分組分配組號,第二遍天然是給命名組分配組號。所以,命名組的組號是大於未命名組的組號。(說這些工做原理,對咱們使用後向引用沒有什麼做用,就是理解一下,內部工做原理而已)

C.也不是全部的組都會分配組號,咱們可使用(:?exp)來禁止分配組號。 

不知道小夥伴們是否看明白了,至少我看了網上關於這塊兒的介紹,都不是很清晰。

下面先看一下後向引用 捕獲 的定義

分類

代碼/語法

說明

捕獲

(exp)

匹配exp,並捕獲文本到自動命名的組裏

(?<name>exp)

匹配exp,並捕獲文本到名稱爲name的組裏,也能夠寫成(?'name'exp)

(?:exp)

匹配exp,不捕獲匹配的文本,也不給此分組分配組號

 先來對上面的三個語法理解一下:

(exp) 就是分組,使用() ,exp就是分組內的子表達式 ,這個在上面分組中已經說明了

(?<name>exp)或 (?’name’exp) 就是組分組命名,只是有兩種寫法而已

(?:exp)exp表達式不會被捕獲到某個組裏,也不會分配組號,但不會改變正則處理方式,確定不少小盆友要問,爲啥要有這個東西,要他何用?

你們看一下下面這個示例:

^([1-9][0-9]*|0)$  表示匹配0-9的整數

再看下面這個

^(?:[1-9][0-9]*|0)$ 也是匹配0-9的整數,可是使用了非捕獲組

做用呢?兩個字:效率

由於咱們定義了組,可是咱們只是爲了使用組來限定範圍開始和結束,並非爲了後向引用,所以使用非捕獲組來禁上分配組號和保存到組裏,極大的提升了檢索效率。

有了上面的理解,我纔好寫點示例,先理論後實踐。 

在進行示例前,咱們先複習如下上節學到的元字符

   *    匹配前面的子表達式任意次。例如,zo* 能匹配「z」,「zo」以及「zoo」。*等價於{ 0,}。

   +    匹配前面的子表達式一次或屢次(大於等於1次)。例如,「zo +」能匹配「zo」以及「zoo」,但不能匹配「z」。+等價於{ 1,}。

   ?    匹配前面的子表達式零次或一次。例如,「do (es) ?」能夠匹配「do」或「does」中的「do」。?等價於{ 0,1}。  

   \w  匹配包括下劃線的任何單詞字符。相似但不等價於「[A-Za-z0-9_]」,這裏的"單詞"字符使用Unicode字符集。

   \b  匹配一個單詞邊界,也就是指單詞和空格間的位置(即正則表達式的「匹配」有兩種概念,一種是匹配字符,一種是匹配位置,這裏的\b就是匹配位置的)。例如,「er\b」能夠匹配「never」中的「er」,但不能匹配「verb」中的「er」。       

   \s  匹配任何不可見字符,包括空格、製表符、換頁符等等。等價於[ \f\n\r\t\v]。

//後向引用

//在後向引用前,咱們先熟悉一下單詞的查找  
//複習一下前面學的幾個元字符
// * 匹配前面的子表達式任意次。例如,zo* 能匹配「z」,「zo」以及「zoo」。*等價於{ 0,}。
// + 匹配前面的子表達式一次或屢次(大於等於1次)。例如,「zo +」能匹配「zo」以及「zoo」,但不能匹配「z」。+等價於{ 1,}。
// ? 匹配前面的子表達式零次或一次。例如,「do (es) ?」能夠匹配「do」或「does」中的「do」。?等價於{ 0,1}。  
// \w 匹配包括下劃線的任何單詞字符。相似但不等價於「[A-Za-z0-9_]」,這裏的"單詞"字符使用Unicode字符集。
// \b 匹配一個單詞邊界,也就是指單詞和空格間的位置(即正則表達式的「匹配」有兩種概念,一種是匹配字符,一種是匹配位置,這裏的\b就是匹配位置的)。例如,「er\b」能夠匹配「never」中的「er」,但不能匹配「verb」中的「er」。       
// \s 匹配任何不可見字符,包括空格、製表符、換頁符等等。等價於[ \f\n\r\t\v]。
string str1 = "zoo zoo hello how you mess ok ok home house miss miss yellow";

//示例一:查找單詞中以e結尾的,並將單詞替換爲了*
string regexStr1 = @"\w+e\b";
Console.WriteLine("示例一:" + Regex.Replace(str1, regexStr1,"*"));

//示例二:查詢單詞中以h開頭的,並將單詞替換爲#
string regexStr2 = @"\bh\w+";
Console.WriteLine("示例二:" + Regex.Replace(str1, regexStr2, "#"));

//示例三:查找單詞中有重疊ll的單詞,將單詞替換爲@
string regexStr3 = @"\b\w+l+\w+\b";
Console.WriteLine("示例三:" + Regex.Replace(str1, regexStr3, "@"));

此外,咱們說到了分組及編號,那麼如何取到某個分組的匹配文本呢?

使用 \1 表示取第一個分組的匹配文本 

//使用 \1 表明第一個分組 組號爲1的匹配文本
//示例四:查詢單詞中有兩個重複的單詞,替換爲%  
string regexStr4 = @"(\b\w+\b)\s+\1";
Console.WriteLine("示例四:" + Regex.Replace(str1, regexStr4, "%"));
//上面示例中,第一個分組匹配任意一個單詞 \s+ 表示任意空字符 \1 表示匹配和第一個分組相同

 別名定義 (?<name>exp)  ,別名後向引用 \k<name> 

//使用別名 代替 組號 ,別名定義 (?<name>exp)  ,別名後向引用 \k<name>
//示例五:使用別名後向引用 查詢 查詢單詞中有兩個重複的單詞,替換爲%%  
string regexStr5 = @"(?<myRegWord>\b\w+\b)\s+\k<myRegWord>";
Console.WriteLine("示例五:"+Regex.Replace(str1, regexStr5, "%%"));

 運行結果以下:

3. 零寬斷言

什麼!?什麼!?對你沒看錯,這段題目叫「零寬斷言」(頓時1W頭艹尼馬奔騰而過!!!!)

原本正則表達式學到本節,小夥伴們漸漸感受看着有點吃力了,還來這麼一個名字。

不過,不要忘記,咱們這一系列的文章叫「.NET 進階」既然是進階,天然就有不少有難度的問題要解決,咱們仍是先看一下這個概念的意思吧!

什麼是零寬斷言?

咱們有常常要查詢某些文本某個位置前面或後面的東西,就像 ^  $  \b同樣,指定一個位置,這個位置須要知足必定的條件(斷言),咱們把這個稱作 零寬斷言 

分類

代碼/語法

說明

零寬斷言

(?=exp)

匹配exp前面的位置

(?<=exp)

匹配exp後面的位置

(?!exp)

匹配後面跟的不是exp的位置

(?<!exp)

匹配前面不是exp的位置

看上面的表,零寬斷言一共有四個類型的位置判斷寫法

咱們先舉幾個示例來看看,TMD零寬斷言到底解決了什麼問題?

//零寬斷言
//示例一:將下面字符串每三位使用逗號分開
string stringFist = "dfalrewqrqwerl43242342342243434abccc";
string regexStringFist = @"((?=\w)\w{3})";
string newStrFist = String.Empty;
Regex.Matches(stringFist, regexStringFist).Cast<Match>().Select(m=>m.Value).ToList<string>().ForEach(m => newStrFist += (m+","));
Console.WriteLine("示例一:" + newStrFist.TrimEnd(','));

//示例二:查詢字符串中,兩個空格之間的全部數字
string FindNumberSecond = "asdfas 3 dfasfas3434324 9 8888888 7 dsafasd342";
string regexFindNumberSecond = @"((?<=\s)\d(?=\s))";
string newFindNumberSecond = String.Empty;
Regex.Matches(FindNumberSecond, regexFindNumberSecond).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newFindNumberSecond += (m + " "));
Console.WriteLine("示例二:" + newFindNumberSecond);

運行結果以下:

?=exp)也叫零寬度正預測先行斷言,它斷言自身出現的位置的後面能匹配表達式exp。

(?<=exp)也叫零寬度正回顧後發斷言,它斷言自身出現的位置的前面能匹配表達式exp。

4.  負向零寬斷言

實在無語了,零寬斷言剛理解完,又來了一個負向零寬斷言,真是很是的坑爹。

解釋這個概念已經很是無力了,除非你不是地球人。但這個東東自己並不難使用,咱們直接解決一個問題。

//負向零寬斷言
//示例:查找單詞中包含x而且x前面不是o的全部單詞
string strThird = "hot example how box house ox xerox his fox six my";
string regexStrThird = @"\b\w*[^o]x\w*\b";
string newStrThird = String.Empty;
Regex.Matches(strThird, regexStrThird).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newStrThird += (m + " "));
Console.WriteLine("示例一:" + newStrThird);
//咱們發現以上寫法,若是以x開頭的單詞,就會出錯,緣由是[^o]必需要匹配一個非o的字符
//爲了解決以上問題,咱們須要使用負向零寬斷言 (?<!o])負向零寬斷言能解決這樣的問題,由於它只匹配一個位置,並不消費任何字符
//改進之後以下
string regexStrThird2 = @"\b\w*(?<!o)x\w*\b";
string newStrThird2 = String.Empty;
Regex.Matches(strThird, regexStrThird2).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newStrThird2 += (m + " "));
Console.WriteLine("示例二:" + newStrThird2);

//示例三:如查詢上面示例,可是要求區配必須含o但 後面不能有x 則要使用 (?!x)
string regexStrThird3 = @"\b\w*o(?!x)\w*\b";
string newStrThird3 = String.Empty;
Regex.Matches(strThird, regexStrThird3).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newStrThird3 += (m + " "));
Console.WriteLine("示例三:" + newStrThird3);

運行結果以下:

再舉一個示例:

//實例一:取到<div name='Fist'></div>之內的內容   使用零寬斷言 正負斷言就能夠解決了
//如下爲模擬一個HTML表格數據
StringBuilder strHeroes =new StringBuilder();
strHeroes.Append("<table>");
strHeroes.Append("<tr><td>武林高手</td></tr>");
strHeroes.Append("<tr><td>");
strHeroes.Append("<div name='Fist'>");
strHeroes.Append("<div>歐陽鋒</div>");
strHeroes.Append("<div>白駝山</div>");
strHeroes.Append("<div>蛤蟆功</div>");
strHeroes.Append("</div>");

strHeroes.Append("<div>");
strHeroes.Append("<div>黃藥師</div>");
strHeroes.Append("<div>桃花島</div>");
strHeroes.Append("<div>彈指神通</div>");
strHeroes.Append("</div>");

strHeroes.Append("</td></tr>");
strHeroes.Append("</table>");
            
Console.WriteLine("原字符串:"+strHeroes.ToString());
          
string newTr = String.Empty;
string regexTr = @"(?<=<div name='Fist'>).+(?=</div>)";
Regex.Matches(strHeroes.ToString(),regexTr).Cast
<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newTr += (m + "\n")); Console.WriteLine(Regex.IsMatch(strHeroes.ToString(), regexTr)); Console.WriteLine("實例一:"+newTr);

運行結果以下:

5. 註釋

正則表達式很長的時候,很難讀懂,因些他有專門的註釋方法,主要有兩種寫法

A.經過語法(?#comment) 

例如:\b\w*o(?!x)(?#o後面不包含x)\w*\b  紅色部分是註釋,他不對錶達式產生任何影響

B.啓用忽略模式裏的空白符選項的多行註釋法

例如:

//正則表達式註釋
//重寫上面的例子,採用多行註釋法
string regexStrThird4 = @"\b         #限定單詞開頭
                          \w*        #任意長度字母數字及下劃線
                          o(?!x)     #含o字母而且後面的一個字母不是x
                          \w*        #任意長度字母數字及下劃線
                          \b         #限定單詞結尾
                          ";
string newStrThird4 = String.Empty;
Regex.Matches(strThird, regexStrThird4,RegexOptions.IgnorePatternWhitespace).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newStrThird4 += (m + " "));
Console.WriteLine("示例四:" + newStrThird4);

運行結果同上。

6. 註釋貪婪與懶惰

這個比較好理解,首先,懶惰是針對重複匹配模式來講的,咱們先看一下下面的表 懶惰的限定符以下:

懶惰限定符

代碼/語法

說明

*?

重複任意次,但儘量少重複

+?

重複1次或更屢次,但儘量少重複

??

重複0次或1次,但儘量少重複

{n,m}?

重複nm次,但儘量少重複

{n,}?

重複n次以上,但儘量少重複

 經過示例來看

//懶惰限定符
string LazyStr = "xxyxy";
string regexLazyStr = @"x.*y";
string regexLazyStr2 = @"x.*?y";
string newLazyStr = String.Empty;
Regex.Matches(LazyStr, regexLazyStr).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newLazyStr += (m + " "));
string newLazyStr2 = String.Empty;
Regex.Matches(LazyStr, regexLazyStr2).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newLazyStr2 += (m + " "));
Console.WriteLine("貪婪模式:" + newLazyStr);
Console.WriteLine("懶惰模式:" + newLazyStr2);

運行結果以下:

咱們能夠看出:

懶惰匹配,也就是匹配儘量少的字符。

相反,貪婪模式則儘量多的匹配字符

貪婪模式均可以被轉化爲懶惰匹配模式,只要在它後面加上一個問號? 

7.處理與選項

經常使用的處理選項

名稱

說明

IgnoreCase(忽略大小寫)

匹配時不區分大小寫。

Multiline(多行模式)

更改^和$的含義,使它們分別在任意一行的行首和行尾匹配,而不只僅在整個字符串的開頭和結尾匹配。(在此模式下,$的精確含意是:匹配\n以前的位置以及字符串結束前的位置.)

Singleline(單行模式)

更改.的含義,使它與每個字符匹配(包括換行符\n)。

IgnorePatternWhitespace(忽略空白)

忽略表達式中的非轉義空白並啓用由#標記的註釋。

ExplicitCapture(顯式捕獲)

僅捕獲已被顯式命名的組。

這個咱們在前面已經不少次用到了,好比 註釋的示例。 

.NET 正則表達式中,咱們使用RegexOptions 枚舉來完成。

上一節在說到.NET經常使用正規表達式方法時簡單做了說明,下面咱們把.NET RegexOptions 枚舉的各個值列舉說明一下

提供用於設置正則表達式選項的枚舉值。此枚舉有一個 FlagsAttribute 屬性,容許其成員值按位組合

Compiled:指定將正則表達式編譯爲程序集。這會產生更快的執行速度,但會增長啓動時間。

CultureInvariant:指定忽略語言中的區域性差別。有關更多信息,請參見 在 RegularExpressions 命名空間中執行不區分區域性的操做

ECMAScript:爲表達式啓用符合 ECMAScript 的行爲。該值只能與 IgnoreCaseMultiline 和 Compiled 值一塊兒使用。該值與其餘任何值一塊兒使用均將致使異常。

ExplicitCapture:指定有效的捕獲僅爲形式爲 (?<name>...) 的顯式命名或編號的組。這使未命名的圓括號能夠充當非捕獲組,而且不會使表達式的語法 (?:...) 顯得笨拙。

IgnoreCase:指定不區分大小寫的匹配。

IgnorePatternWhitespace:消除模式中的非轉義空白並啓用由 # 標記的註釋。可是,IgnorePatternWhitespace 值不會影響或消除字符類中的空白。

Multiline:多行模式。更改 ^ 和 $ 的含義,使它們分別在任意一行的行首和行尾匹配,而不只僅在整個字符串的開頭和結尾匹配。

None:指定不設置選項。

RightToLeft:指定搜索從右向左而不是從左向右進行。

Singleline:指定單行模式。更改點 (.) 的含義,使它與每個字符匹配(而不是與除 /n 以外的每一個字符匹配)。

示例:

//處理選項
//Compiled表示編譯爲程序集,使效率提升   
//IgnoreCase表示匹配不分大小寫
Regex rx = new Regex(@"\b(?<word>\w+)\s+(\k<word>)\b",RegexOptions.Compiled | RegexOptions.IgnoreCase);
string myWords = "hello hello How Hi hi are you you apple o o ";
string newMyWords = String.Empty;
rx.Matches(myWords).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newMyWords += (m + ","));
Console.WriteLine("相同的單詞有:" + newMyWords.Trim(','));

運行結果以下:

8. 判斷表達式 

     這裏須要用到如下的語法構造:

  • (?'group') 把捕獲的內容命名爲group,並壓入堆棧(Stack)
  • (?'-group') 從堆棧上彈出最後壓入堆棧的名爲group的捕獲內容,若是堆棧原本爲空,則本分組的匹配失敗
  • (?(group)yes|no) 若是堆棧上存在以名爲group的捕獲內容的話,繼續匹配yes部分的表達式,不然繼續匹配no部分
  • (?!) 零寬負向先行斷言,因爲沒有後綴表達式,試圖匹配老是失敗 

   能夠看到,實際上就是一個除|擇一以後的,另外一種判斷表達,這裏算是個總結 ,下面幾種寫法帶有判斷性質語法:

     (1)、A|B,這個是最基本的,A或者B,其實這個不能算判斷
     (2)、(?(expression)yes-expression|no-expression),其中no-expression爲可選項,意爲,若是expression成立,則要求匹配yes-expression,不然要求匹配no-expression
     (3)、(?(group-name)yes-expressioin|no-expression),其中no-expression爲可選項,意爲,若是名爲group-name的組匹配成功,則要求匹配yes-expression,不然要求匹配no-expression
     判斷表達式仍是很好理解的,惟有一點要注意:@"(?(A)A|B)"不能匹配"AA",咱們應該這樣寫Regex: @」(?(A)AA|B)」,請注意,判斷式中的內容並不會作爲yes-expression或no-expression表達式的一部分。 

      (?'group') 和(?'group') 一般用做平衡組匹配,好比咱們匹配html等對稱標籤時,對於不對稱的標籤,則匹配失敗  

本節全部源代碼貼上來 

  1 //示例:重複單字符 和 重複分組字符
  2 //重複 單個字符
  3 Console.WriteLine("請輸入一個任意字符串,測試分組:");
  4 string inputStr = Console.ReadLine();
  5 string strGroup1 = @"a{2}";
  6 Console.WriteLine("單字符重複2兩次替換爲22,結果爲:"+Regex.Replace(inputStr, strGroup1,"22"));
  7 //重複 多個字符 使用(abcd){n}進行分組限定
  8 string strGroup2 = @"(ab\w{2}){2}";
  9 Console.WriteLine("分組字符重複2兩次替換爲5555,結果爲:" + Regex.Replace(inputStr, strGroup2, "5555"));
 10 
 11 Console.WriteLine("\n");
 12 
 13 //示例:校驗IP4地址(如:192.168.1.4,爲四段,每段最多三位,每段最大數字爲255,而且第一位不能爲0)
 14 string regexStrIp4 = @"^(((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?))$";
 15 Console.WriteLine("請輸入一個IP4地址:");
 16 string inputStrIp4 = Console.ReadLine();
 17 Console.WriteLine(inputStrIp4 + " 是否爲合法的IP4地址:" + Regex.IsMatch(inputStrIp4, regexStrIp4));
 18 Console.WriteLine("請輸入一個IP4地址:");
 19 string inputStrIp4Second = Console.ReadLine();           
 20 Console.WriteLine(inputStrIp4 + " 是否爲合法的IP4地址:" + Regex.IsMatch(inputStrIp4Second, regexStrIp4));
 21            
 22 //後向引用
 23 
 24 //在後向引用前,咱們先熟悉一下單詞的查找  
 25 //複習一下前面學的幾個元字符
 26 // * 匹配前面的子表達式任意次。例如,zo* 能匹配「z」,「zo」以及「zoo」。*等價於{ 0,}。
 27 // + 匹配前面的子表達式一次或屢次(大於等於1次)。例如,「zo +」能匹配「zo」以及「zoo」,但不能匹配「z」。+等價於{ 1,}。
 28 // ? 匹配前面的子表達式零次或一次。例如,「do (es) ?」能夠匹配「do」或「does」中的「do」。?等價於{ 0,1}。  
 29 // \w 匹配包括下劃線的任何單詞字符。相似但不等價於「[A-Za-z0-9_]」,這裏的"單詞"字符使用Unicode字符集。
 30 // \b 匹配一個單詞邊界,也就是指單詞和空格間的位置(即正則表達式的「匹配」有兩種概念,一種是匹配字符,一種是匹配位置,這裏的\b就是匹配位置的)。例如,「er\b」能夠匹配「never」中的「er」,但不能匹配「verb」中的「er」。       
 31 // \s 匹配任何不可見字符,包括空格、製表符、換頁符等等。等價於[ \f\n\r\t\v]。
 32 string str1 = "zoo zoo hello how you mess ok ok home house miss miss yellow";
 33 
 34 //示例一:查找單詞中以e結尾的,並將單詞替換爲了*
 35 string regexStr1 = @"\w+e\b";
 36 Console.WriteLine("示例一:" + Regex.Replace(str1, regexStr1,"*"));
 37 
 38 //示例二:查詢單詞中以h開頭的,並將單詞替換爲#
 39 string regexStr2 = @"\bh\w+";
 40 Console.WriteLine("示例二:" + Regex.Replace(str1, regexStr2, "#"));
 41 
 42 //示例三:查找單詞中有重疊ll的單詞,將單詞替換爲@
 43 string regexStr3 = @"\b\w+l+\w+\b";
 44 Console.WriteLine("示例三:" + Regex.Replace(str1, regexStr3, "@"));
 45 
 46 //使用 \1 表明第一個分組 組號爲1的匹配文本
 47 //示例四:查詢單詞中有兩個重複的單詞,替換爲%  
 48 string regexStr4 = @"(\b\w+\b)\s+\1";
 49 Console.WriteLine("示例四:" + Regex.Replace(str1, regexStr4, "%"));
 50 //上面示例中,第一個分組匹配任意一個單詞 \s+ 表示任意空字符 \1 表示匹配和第一個分組相同
 51 
 52 //使用別名 代替 組號 ,別名定義 (?<name>exp)  ,別名後向引用 \w<name>
 53 //示例五:使用別名後向引用 查詢 查詢單詞中有兩個重複的單詞,替換爲%%  
 54 string regexStr5 = @"(?<myRegWord>\b\w+\b)\s+\k<myRegWord>";
 55 Console.WriteLine("示例五:"+Regex.Replace(str1, regexStr5, "%%"));
 56 
 57 //零寬斷言
 58 //示例一:將下面字符串每三位使用逗號分開
 59 string stringFist = "dfalrewqrqwerl43242342342243434abccc";
 60 string regexStringFist = @"((?=\w)\w{3})";
 61 string newStrFist = String.Empty;
 62 Regex.Matches(stringFist, regexStringFist).Cast<Match>().Select(m=>m.Value).ToList<string>().ForEach(m => newStrFist += (m+","));
 63 Console.WriteLine("示例一:" + newStrFist.TrimEnd(','));
 64 
 65 //示例二:查詢字符串中,兩個空格之間的全部數字
 66 string FindNumberSecond = "asdfas 3 dfasfas3434324 9 8888888 7 dsafasd342";
 67 string regexFindNumberSecond = @"((?<=\s)\d(?=\s))";
 68 string newFindNumberSecond = String.Empty;
 69 Regex.Matches(FindNumberSecond, regexFindNumberSecond).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newFindNumberSecond += (m + " "));
 70 Console.WriteLine("示例二:" + newFindNumberSecond);
 71 
 72 //負向零寬斷言
 73 //示例:查找單詞中包含x而且x前面不是o的全部單詞
 74 string strThird = "hot example how box house ox xerox his fox six my";
 75 string regexStrThird = @"\b\w*[^o]x\w*\b";
 76 string newStrThird = String.Empty;
 77 Regex.Matches(strThird, regexStrThird).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newStrThird += (m + " "));
 78 Console.WriteLine("示例一:" + newStrThird);
 79 //咱們發現以上寫法,若是以x開頭的單詞,就會出錯,緣由是[^o]必需要匹配一個非o的字符
 80 //爲了解決以上問題,咱們須要使用負向零寬斷言 (?<!o])負向零寬斷言能解決這樣的問題,由於它只匹配一個位置,並不消費任何字符
 81 //改進之後以下
 82 string regexStrThird2 = @"\b\w*(?<!o)x\w*\b";
 83 string newStrThird2 = String.Empty;
 84 Regex.Matches(strThird, regexStrThird2).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newStrThird2 += (m + " "));
 85 Console.WriteLine("示例二:" + newStrThird2);
 86 
 87 //示例三:如查詢上面示例,可是要求區配必須含o但 後面不能有x 則要使用 (?!x)
 88 string regexStrThird3 = @"\b\w*o(?!x)\w*\b";
 89 string newStrThird3 = String.Empty;
 90 Regex.Matches(strThird, regexStrThird3).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newStrThird3 += (m + " "));
 91 Console.WriteLine("示例三:" + newStrThird3);
 92 
 93 //正則表達式註釋
 94 //重寫上面的例子,採用多行註釋法
 95 string regexStrThird4 = @"  \b         #限定單詞開頭
 96                             \w*        #任意長度字母數字及下劃線
 97                             o(?!x)     #含o字母而且後面的一個字母不是x
 98                             \w*        #任意長度字母數字及下劃線
 99                             \b         #限定單詞結尾
100                             ";
101 string newStrThird4 = String.Empty;
102 Regex.Matches(strThird, regexStrThird4,RegexOptions.IgnorePatternWhitespace).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newStrThird4 += (m + " "));
103 Console.WriteLine("示例四:" + newStrThird4);
104 
105 //懶惰限定符
106 string LazyStr = "xxyxy";
107 string regexLazyStr = @"x.*y";
108 string regexLazyStr2 = @"x.*?y";
109 string newLazyStr = String.Empty;
110 Regex.Matches(LazyStr, regexLazyStr).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newLazyStr += (m + " "));
111 string newLazyStr2 = String.Empty;
112 Regex.Matches(LazyStr, regexLazyStr2).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newLazyStr2 += (m + " "));
113 Console.WriteLine("貪婪模式:" + newLazyStr);
114 Console.WriteLine("懶惰模式:" + newLazyStr2);               
115 
116 //處理選項
117 //Compiled表示編譯爲程序集,使效率提升   
118 //IgnoreCase表示匹配不分大小寫
119 Regex rx = new Regex(@"\b(?<word>\w+)\s+(\k<word>)\b",RegexOptions.Compiled | RegexOptions.IgnoreCase);
120 string myWords = "hello hello How Hi hi are you you apple o o ";
121 string newMyWords = String.Empty;
122 rx.Matches(myWords).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newMyWords += (m + ","));
123 Console.WriteLine("相同的單詞有:" + newMyWords.Trim(','));
124 
125 //實例一:取到<div name='Fist'></div>之內的內容   使用零寬斷言 正負斷言就能夠解決了
126 //如下爲模擬一個HTML表格數據
127 StringBuilder strHeroes =new StringBuilder();
128 strHeroes.Append("<table>");
129 strHeroes.Append("<tr><td>武林高手</td></tr>");
130 strHeroes.Append("<tr><td>");
131 strHeroes.Append("<div name='Fist'>");
132 strHeroes.Append("<div>歐陽鋒</div>");
133 strHeroes.Append("<div>白駝山</div>");
134 strHeroes.Append("<div>蛤蟆功</div>");
135 strHeroes.Append("</div>");
136 
137 strHeroes.Append("<div>");
138 strHeroes.Append("<div>黃藥師</div>");
139 strHeroes.Append("<div>桃花島</div>");
140 strHeroes.Append("<div>彈指神通</div>");
141 strHeroes.Append("</div>");
142 
143 strHeroes.Append("</td></tr>");
144 strHeroes.Append("</table>");
145             
146 Console.WriteLine("原字符串:"+strHeroes.ToString());
147           
148 string newTr = String.Empty;
149 string regexTr = @"(?<=<div name='Fist'>).+(?=</div>)";
150     Regex.Matches(strHeroes.ToString(),regexTr).Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(m => newTr += (m + "\n"));
151 Console.WriteLine(Regex.IsMatch(strHeroes.ToString(), regexTr));
152 Console.WriteLine("實例一:"+newTr);
View Code

==============================================================================================  

 返回目錄

 <若是對你有幫助,記得點一下推薦哦,若有

有不明白或錯誤之處,請多交流>  

<對本系列文章閱讀有困難的朋友,請先看《.net 面向對象編程基礎》>

<轉載聲明:技術須要共享精神,歡迎轉載本博客中的文章,但請註明版權及URL>

.NET 技術交流羣:467189533    .NET 程序設計

==============================================================================================   

相關文章
相關標籤/搜索