nbe*_*ans 1 .net c# regex balancing-groups
我有一个基本的文本模板引擎,使用这样的语法:
foo bar
%IF MY_VAR
some text
%IF OTHER_VAR
some other text
%ENDIF
%ENDIF
bar foo
Run Code Online (Sandbox Code Playgroud)
我有一个正则表达式的问题,我用来解析它,因为它没有考虑嵌套的IF/ENDIF块.
我正在使用的当前正则表达式是: %IF (?<Name>[\w_]+)(?<Contents>.*?)%ENDIF
我一直在阅读平衡捕获组(.NET的正则表达式库的一个特性),因为我理解这是支持.NET中"递归"正则表达式的推荐方法.
我一直在玩平衡组,到目前为止已经提出了以下建议:
(
(
(?'Open'%IF\s(?<Name>[\w_]+))
(?<Contents>.*?)
)+
(
(?'Close-Open'%ENDIF)(?<Remainder>.*?)
)+
)*
(?(Open)(?!))
Run Code Online (Sandbox Code Playgroud)
但这并不完全符合我的预期.例如,它捕获了很多空组.救命?
要使用平衡的IF语句捕获整个IF/ENDIF块,可以使用此正则表达式:
%IF\s+(?<Name>\w+)
(?<Contents>
(?> #Possessive group, so . will not match IF/ENDIF
\s|
(?<IF>%IF)| #for IF, push
(?<-IF>%ENDIF)| #for ENDIF, pop
. # or, anything else, but don't allow
)+
(?(IF)(?!)) #fail on extra open IFs
) #/Contents
%ENDIF
Run Code Online (Sandbox Code Playgroud)
这里的要点是:你不能在Match每个命名组中的一个以上捕获.(?<Name>\w+)例如,您将只获得一组最后捕获的值.在我正则表达式,我不停的Name和Contents你简单的正则表达式的群体,并限制了内部的平衡Contents组-正则表达式仍包裹在IF和ENDIF.
如果您的数据更复杂,那么会变得有趣.例如:
%IF MY_VAR
some text
%IF OTHER_VAR
some other text
%ENDIF
%IF OTHER_VAR2
some other text 2
%ENDIF
%ENDIF
%IF OTHER_VAR3
some other text 3
%ENDIF
Run Code Online (Sandbox Code Playgroud)
在这里,你会得到两场比赛,一个MY_VAR,一个用于OTHER_VAR3.如果你想捕获MY_VAR内容上的两个ifs ,你必须重新运行它的Contents组上的正则表达式(你可以通过使用前瞻来解决它,如果你必须 - 包装整个正则表达式(?=...),但你需要把它以某种方式使用位置和长度进入逻辑结构).
现在,我不会解释太多,因为它似乎得到了基础知识,但是关于内容组的简短说明 - 我使用占有性组来避免回溯.否则,点最终可能匹配整个IFs并打破平衡.组上的惰性匹配行为类似(( )+?而不是(?> )+).