分組捕獲 - ()
就是用括號把要匹配的內容擴起來
命名分組捕獲 - (?<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的驗證
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對應。");
}
可以不使用條件表達式,在代碼中判斷也可以。
做這個例子的意義是什麼呢?意思就是說明所謂的“平衡組”的工作原理,是檢查是否還有沒有彈出棧的分組,如果有,則表明不是配對存在的,反之是配對出現的。這就是常用的平衡組意義。