正則表達式之分組捕獲、條件表達式、平衡組

分組捕獲 - ()

就是用括號把要匹配的內容擴起來

 

命名分組捕獲 - (?<name>)或(?'name')

 

就是在分組捕獲的基礎上,增加?<分組名>或?'分組名'

 

爲了鞏固印象,舉個例子

axaxbxxxbxxx

分組捕獲:

(a)x

一次匹配結果,將會得到ax,其中分組1捕獲結果爲a

命名分組捕獲:

同樣的文本,使用(?<data>a)x

一次匹配結果,你可以用分組序號1,或是分組名data獲得分組匹配結果a

 

條件表達式 - (?<data>...)(?(data)yes|no)
非常高興,我們開始切入正題了。條件表達式讓我們的正則具有了一定的邏輯判斷能力。比如:

文本:

文本[12]和【56】abcd

要求:

找到[]或【】中間的數字

我們自然要考慮[】或是【]這兩種錯誤的配對關係,這正好使用條件表達式

(?<=(?<o1>/[)|(?<o2>/【))/d+(?=(?(o1)/]|/】))

別看暈了,容我慢慢給你講明這個表達式的書寫思路。

首先,我們要的是中間的數字,如果有其他的怎麼辦?當然是整個丟掉,我們不打算跑題的節外生枝把[文字]也捕獲進來,或是具有容錯的[ 12]捕獲進來,我們在討論問題,就題目而論就可以了。

我首先想到的應該使用(?<=exp)/d+(?=exp2)的寫法,這樣最終結果就只有數字了。

那麼,exp如何寫呢?

很簡單,(?<=[/[/【]),這樣的話,我們無法做到前後的括號類型配對,好吧,我們把[和【分別捕獲,並記錄對應的分組,這樣方便後面可以引用。

前面部分就變成:

(?<=(?<o1>/[)|(?<o2>【))

就單這一部分,我們就捕獲到了一個位置,前面是[或是【的位置,而如果前面是[,則分組o1捕獲到,反之o2捕獲到,到目前爲止,都關係不大。但爲了能得到對應的匹配,我們配合條件表達式,就方便很多了。

exp2

我們可以寫爲

(?=(?(o1)/]|/】))

什麼意思呢?

(?(o1)/]|/】)

表示這裏檢查o1分組捕獲情況,如果捕獲成功,則執行/]的匹配,反之,執行/】的匹配。這樣,我們用條件表達式,就可以確定[]和【】的對應關係了。

平衡組(?<group>)(?<-group>)(?(group)?!)

這個名詞已經用了很久了,無從考證出處,《c#字符串和正則表達式》書中沒有提到,無所謂出處了,但這個名字,倒是讓一個簡單的概念變得複雜了,可能我也愚笨,弄了好久才明白,其實很簡單的東西。

說白了,就是命名分組的一個高級用法,命名分組,我們寫(?<group>)可以把捕獲到的內容壓入堆棧,而另一個高級的用法,是(?<-group>)可以把已經壓入堆棧的元素彈出堆棧,(?(group)?!)則是我們剛纔看到的條件表達式,如果捕獲到了group分組,則執行?!表達式,?!就是表達式爲假,匹配失敗。

舉個不用標準寫法的例子,可能更容易理解一點。

例如文本:

xxxxaxxaxxaxxbxxbxxbxxxx

我們可以用代碼方式做a...b的驗證

[c-sharp] view plaincopy

string test = "xxxxaxxaxxaxxbxxbxxbxxxx";  

Match m = Regex.Match(test, "a((?<o>a)|(?<-o>b)|[^ab]+)+b");  

if (m.Groups["o"].Captures.Count > 0)  

{  

    Console.WriteLine("錯誤,不是完整的a...b對應關係,有單獨的a存在");  

}  

else  

{  

    Console.WriteLine("很好,a...b對應。");  

}  

可以不使用條件表達式,在代碼中判斷也可以。

做這個例子的意義是什麼呢?意思就是說明所謂的“平衡組”的工作原理,是檢查是否還有沒有彈出棧的分組,如果有,則表明不是配對存在的,反之是配對出現的。這就是常用的平衡組意義。

發佈了13 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章