我試了一下,貌似沒有問題。當然也很可能有問題,因為Regex我也是剛入門。
這個運算式是這樣的:
^
[^<>]*
((?'open'<[^<>]*)+
(?'close-open'[^<>]*>)+)+
(?(open)(?!))$
作用是判定一個字串中的角括弧是否配對,如果都配對則返回整個串,否則不返回任何匹配。
首先寫下這個東西:
^
Expr
$
表示進行整串匹配,也就是要判斷整個字串是否符合
Expr表示的模式。
哦,使用這個Regex的時候記得開啟忽略空白字元。
如果Regex支援宏多好,把<>修改為()時就不用費太多力氣了。
Expr::=
Expr1::=[^<>]*
Expr2::=(
(?'open'<[^<>]*)+
(?'close-open'[^<>]*>)+
)+
Expr3::=(?(open)(?!))
[^<>]*不用多說,匹配'<'和'>'之外的任一字元任意多次,這並不是關鍵。
關鍵是Expr2。
Expr2中有兩個關鍵構造,(?'
Name'
Expr)和(?'
Name2-
Name1'
Expr)
第一個我稱之為顯式命名組,第二個人們稱為平衡組。
這是.net framework特有的構造。
顯式命名組將捕獲到的文本存入名稱為
Name的堆棧中。所謂捕獲到的文本,就是Expr所匹配的文本,(?'
Name'
Expr)和
Expr的區別在於Expr捕獲的文本沒有存到一個堆棧中,或者說沒有存到一個組中。
(?'
Name2-
Name1'
Expr)除了將文本捕獲到Name2組中,還pop名為Name的堆棧。
現在我們可以看看Expr2,其意義是“<[^<>]*”至少重複一次,後跟至少一個“[^<>]*>”。具幾個匹配這個模式的例子:
<fsd<rew<bvc rewrew>ewr>
然後這整個東西---------->> (?'open'<[^<>]*)+(?'close-open'[^<>]*>)+ <<----------可以重複多次。
可能說的不是太清楚,我覺得這一步很關鍵:
<[^<>]* 的執行個體可以是:<fsdfds、<、<rewrewrew、<fdsfsd dfsfds。
[^<>]*>的執行個體可以是:fdsfsd>、>、w-ww>。
現在你可以想象出來(<[^<>]*)+ ([^<>]*>)+是什麼了。
而 (?'open'<[^<>]*)+(?'close-open'[^<>]*>)+ 和它的唯一區別是,(?'open'...每匹配一次,就push該匹配結果到名為open的堆棧,(?'close-open'...每匹配一次,就從open堆棧pop一個元素。open堆棧是<與>是否配對的指標。
最後Expr3這一部分判斷open堆棧是否為空白,為空白則匹配成功,否則前向斷言(?!),這總是導致匹配失敗。