小括號的作用
分類 代碼/語法 說明
捕獲
(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";如果還有,則匹配失敗 > #最外層的右括號