正則表達式 之領寬斷言


小括號的作用

分類     代碼/語法     說明

捕獲    
      (exp)        匹配exp,並捕獲文本到自動命名的組里
      (?<name>exp)   匹配exp,並捕獲文本到名稱為name的組里,也可以寫成(?'name'exp)
      (?:exp)        匹配exp,不捕獲匹配的文本,也不給此分組分配組號
零寬斷言
      (?=exp)      匹配exp前面的位置
      (?<=exp)      匹配exp后面的位置
      (?!exp)       匹配后面跟的不是exp的位置
      (?<!exp)     匹配前面不是exp的位置
注釋
      (?#comment) 這種類型的分組不對正則表達式的處理產生任何影響,用於提供注釋讓人閱讀

要特別注意的是,零寬斷言是不占用位置的,也就是說,匹配結果里是不會返回它的。

 (?:exp) 既不捕獲匹配的文本,也不給此分組分配組號,這個東西到底有什么用呢?

 (?:exp) 非捕獲組,匹配exp的內容,但不捕獲到組里

至於作用,一般來說是為了節省資源,提高效率
比如說驗證輸入是否為整數,可以這樣寫
^([1-9][0-9]*|0)$
這時候我們需要用到()來限制“|”表示“或”關系的范圍,但我們只是要判斷規則,沒必要把exp匹配的內容保存到組里,這時就可以用非捕獲組了
^(?:[1-9][0-9]*|0)$

  有的時候我們不得不用(),而()默認情況下會將其中exp匹配的內容捕獲到組里,而有些情況我們只是判斷規則,或者后面並不需要對此處()中匹配的內容進行引用時,就沒有必要把它捕獲到組里了,一方面會造成資源的浪費,另一方面會降低效率,這時候就要用到非捕獲組了。

至於這些東西,說是說不明白的,看符號也沒用,最好就是上例子。

復制代碼
//正則表達式牛逼,名詞好牛B,其實好簡單
        static void Main(string[] args)
        {
            //(exp) 匹配exp,並捕獲文本到自動命名的組里
            Regex reg = new Regex(@"A(\w+)A");
            Console.WriteLine(reg.Match("dsA123A"));    //輸出 A123A
            Console.WriteLine(reg.Match("dsA123A").Groups[1]);      //輸出123

            //(?<name>exp)    匹配exp,並捕獲文本到名稱為name的組里,也可以寫成(?'name'exp)
            Regex reg2 = new Regex(@"A(?<num>\w+)A");
            Console.WriteLine(reg2.Match("dsA123A").Groups["num"]); //輸出123

            Regex reg3 = new Regex(@"A(?:\w+A)");
            Console.WriteLine(reg3.Match("dsA123A"));

            Console.WriteLine("==============================");

            //(?=exp)    匹配exp前面的位置  零寬正預測先行斷言
            Regex reg4 = new Regex(@"sing(?=ing)");     //表達式的意思是,我認為在sing的后面會有ing,如果sing后面緊跟着ing,那么這個sing才匹配成功,注意斷言詞不會被匹配
            Console.WriteLine(reg4.Match("ksingkksingingkkk"));     //輸出    sing
            Console.WriteLine(reg4.Match("singddddsingingd").Index);   //輸出 8   輸出8就意味住前面那個sing被沒有被匹配

            //(?<=exp) 匹配exp后面的位置  零寬度正回顧后發斷言
            Regex reg5 = new Regex(@"(?<=wo)man");
            Console.WriteLine(reg5.Match("Hi man Hi woman"));   //輸出 man
            Console.WriteLine(reg5.Match("Hi man Hi woman").Index);     //輸出 12    掰着手指頭算算到底匹配的是哪一個

            //(?!exp)    匹配后面跟的不是exp的位置 零寬度負預測先行斷言
            Regex reg6 = new Regex(@"sing(?!ing)");
            Console.WriteLine(reg6.Match("singing-singabc"));   //輸出 sing
            Console.WriteLine(reg6.Match("singing-singabc").Index); //輸出 8  還得掰着手指頭算算匹配的是哪一個

            //(?<!exp)    匹配前面不是exp的位置 零寬度負回顧后發斷言
            Regex reg7 = new Regex(@"(?<!wo)man");
            Console.WriteLine(reg7.Match("Hi woman Hi man"));   //輸出 man
            Console.WriteLine(reg7.Match("Hi woman Hi man").Index); //輸出 12  算算匹配的是哪一個

            //(?#comment)    不對正則表達式的處理產生任何影響,用於提供注釋讓人閱讀
            Regex reg8 = new Regex("ABC(?#這只是一段注釋而已)DEF");
            Console.WriteLine(reg8.Match("ABCDEFG"));   //輸出 ABCDEF
        }
復制代碼

懶惰匹配

代碼/語法       說明
*?          重復任意次,但盡可能少重復
+?          重復1次或更多次,但盡可能少重復
??           重復0次或1次,但盡可能少重復
{n,m}?         重復n到m次,但盡可能少重復
{n,}?          重復n次以上,但盡可能少重復

如果你細心的留意到,會發現,其實懶惰匹配符只是在原有限定符后面加了個?以表示盡可能少地匹配的意思。

復制代碼
class Program
    {
        //正則表達式牛逼,名詞好牛B,其實好簡單
        static void Main(string[] args)
        {
            //懶惰匹配
            Regex reg1 = new Regex(@"A(\w)*B");
            Console.WriteLine(reg1.Match("A12B34B56B"));    //輸出 A12B34B56B //留意到默認是盡可能多地匹配

            Regex reg2 = new Regex(@"A(\w)*?B"); //\w重復任意次,但盡可能少          
            Console.WriteLine(reg2.Match("A12B34B56B"));   //輸出 A12B

            Regex reg3 = new Regex(@"A(\w)+?");  //\w重復1次或更多次,但盡可能少
            Console.WriteLine(reg3.Match("AB12B34B56B"));        //輸出AB 注意此處測試字符串

            Regex reg4 = new Regex(@"A(\w)??B");  //\w重復0次或1次,但盡可能少
            Console.WriteLine(reg4.Match("A12B34B56B"));    //輸出 空白,匹配失敗,因為至少也要重復\w兩次
            Console.WriteLine(reg4.Match("A1B2B34B56B"));   //輸出 A1B

            Regex reg5 = new Regex(@"A(\w){4,10}?B");       //\w至少重復4次,最多重復10次
            Console.WriteLine(reg5.Match("A1B2B3B4B5B"));   //輸出 A1B2B3B    到了第4個的時候,恰好第4個字符是3只有匹配3后面的那個B了

            Regex reg6 = new Regex(@"A(\w){4,}?");  //\w至少重復4次,最多無上限
            Console.WriteLine(reg5.Match("A1B2B3B4B5B"));   //輸出 A1B2B3B    到了第4個的時候,恰好第4個字符是3只有匹配3后面的那個B了

            Console.ReadKey();
        }
    }
復制代碼

 平衡組

正則表達式平衡組用於匹配左右兩邊開始,結束符號相等數量的內容
  例如,對於字符串"xx <aa <bbb> <bbb> aa> yy>" 左右兩邊的< > 是不等的,如果簡單的<.+>匹配到的是最外層的開始括號<與結束括號 
>之間的內容,但是開始和封閉的括號數量不一致。如果你希望匹配到的是左右括號正常結束的字符串,那么就需要用到平衡組了。

平衡組語法:
  (?'group') 把捕獲的內容命名為group,並壓入堆棧(Stack)
  (?'-group') 從堆棧上彈出最后壓入堆棧的名為group的捕獲內容,如果堆棧本來為空,則本分組的匹配失敗
  (?(group)yes|no) 如果堆棧上存在以名為group的捕獲內容的話,繼續匹配yes部分的表達式,否則繼續匹配no部分
  (?!) 零寬負向先行斷言,由於沒有后綴表達式,試圖匹配總是失敗

復制代碼
        static void Main(string[] args)
        {
            //平衡組 我們現在要匹配最外層的括號的內容
            string strTag = "xx <aa <bbb> <bbb> aa> yy>";   //要匹配的目標是 <aa <bbb> <bbb> aa>  ,注意括號數不等
            Regex reg = new Regex("<.+>");
            Console.WriteLine(reg.Match(strTag));   //輸出 <aa <bbb> <bbb> aa> yy>    看到與希望匹配的目標不一致,主要是因為 < 與 > 的數量不相等

            Regex reg3 = new Regex("<[^<>]*(((?'Open'<)[^<>]*)+((?'-Open'>)[^<>]+))*(?(Open)(?!))>");
            Console.WriteLine(reg3.Match(strTag));  //<aa <bbb> <bbb> aa>   目標正確


            //平衡組最常用的例子,匹配HTML,以下是匹配嵌套DIV里面的內容
            Regex reg2 = new Regex(@"<div[^>]*>[^<>]*(((?'Open'<div[^>]*>)[^<>]*)+((?'-Open'</div>)[^<>]*)+)*(?(Open)(?!))</div>");
            string str = "<a href='http://www.baidu.com'></a><div id='div1'><div id='div2'>你在他鄉還好嗎?</div></div><p></p>";
            Console.WriteLine(reg2.Match(str));  //輸出 <div id='div1'><div id='div2'>你在他鄉還好嗎?</div></div>
            Console.ReadKey();
        }
復制代碼
語法解釋:
< #最外層的左括號 [^<>]* #最外層的左括號后面的不是括號的內容 ( ( (?'Open'<) #碰到了左括號,在黑板上寫一個"Open" [^<>]* #匹配左括號后面的不是括號的內容 )+ ( (?'-Open'>) #碰到了右括號,擦掉一個"Open" [^<>]* #匹配右括號后面不是括號的內容 )+ )* (?(Open)(?!)) #在遇到最外層的右括號前面,判斷黑板上還有沒有沒擦掉的"Open";如果還有,則匹配失敗 > #最外層的右括號

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM