在.Net
中, 正则表达式匹配支持两种高级语法:
匹配到的指定组名(?<Group>...)
根据组名的几种操作方式(?<-Group>)
, (?(Group)yes|no)
指定组名 用?<Group>
或?'Group'
两种语法, 都可以为匹配到的组命名.
1 2 3 4 5 6 7 var reg = new Regex("name:(?'groupName'[a-zA-Z0-9_-]+)"); //var reg = new Regex("name:(?<groupName>[a-zA-Z0-9_-]+)"); var matches = reg.Matches("name:test1,name:test2"); foreach (Match m in matches) { var name = m.Groups["groupName"].Value; }
组堆栈 在使用?<Group>
语法时, .net
会将匹配到的内容压入堆栈stack
. 然后在之后的匹配中, 可以使用语法?<-Group>
从堆栈顶部弹出名字为<Group>
的命名组, 如果堆栈为空, 那么该组匹配失败.
1 2 3 4 5 6 var reg = new Regex("name:(?<nameMatch>(?'stack'{[^{}]+)(?'-stack'}))"); var matches = reg.Matches("name:{abc}"); foreach (Match m in matches) { var name = m.Groups["nameMatch"].Value;//{abc} }
(?(Group)yes|no)
的意义是, 如果堆栈上还存在名字为Group
的组内容是, 执行yes
语句, 否则执行no
语句. 这时候可以使用(?!)
零宽负向先行断言, 由于没有后缀表达式, 试图匹配总是失败. 即如果还存在Group
时, 直接失败.
这几种语法结合起来, 就可以构造递归匹配的方法了. 如匹配类json
格式字符串{l:{l1:{l2:3}}}
.
1 2 3 4 5 6 7 var reg = new Regex(@"\{(?<match>.+)\}"); //匹配到内容 : "l:{l1:{l2:3}}" //存在问题, 如果字符串为 "{l:{ {l1:{l2:3}}}" 也能匹配到全部 var reg = new Regex(@"\{(?<match>(?>[^{}]+|(?<stack>\{(?!\{))|(?<-stack>\}))*(?(stack)(?!)))\}"); // {l:{l1:{l2:3}}} => l:{l1:{l2:3}} // {l:{ {l1:{l2:3}}} => l1:{l2:3} // {l:{ {l1:{ {l2:3}}} => l2:3
解释: 找到第一个{
开始, 命名为match
匹配组, 使用(?>)
非回溯(又名贪婪)匹配法则和固化分组进行内容匹配(对性能好), 匹配到 : 所有不是{}
符号的内容[^{}]+
或者 如果是{
, 而且后面不为{
的内容则压入stack
, 如果是}
, 则弹出stack
. 一直匹配到最后(贪婪模式), 如果最后还有stack
, 则匹配失败({}
数量不正确的情况不会匹配到).
这种语法的帮助在于可以递归匹配内容, 而且判断内容是否正确. 比如做SQL
动态(0 嵌套)解析, 即可使用正则平衡组匹配.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 \{\? #匹配括号开始 -- 有一个括号和问号 (?<DynamicClause> #分组别名DynamicClause (?> #非回溯(也称为 贪婪 )子表达式。 即在贪婪条件下匹配过去满足条件的, #如果碰见后面不满足的,则不会退回字符再查找 #用(?>…)实现固化分组(成功匹配后,回溯时不会考虑这个匹配的字符) #!正常情况则是贪婪匹配,如果碰见不满足的可以退回字符再次查找满足的 [^\{\}]+ #除了{}的字符串 | #或者 \{\?(?<Clause>) #{[0-1个问号]push字符串到Clause -- 括号,可能有个问号,然后把Clause放进去 #命名捕获组,遇到正括弧Clause计数加1 | #或者 \}(?<-Clause>) #}pop字符串Clause -- 反括号,然后把Clause弹出 #狭义平衡组,遇到闭括弧Clause计数减1 )* #0-n个这种字符串 (?(Clause)(?!)) #如果还有Clause匹配失败 ) #分组结束 \} #匹配括号结束 //使用语法 select * from table where row = #row# and IsDel = 0 {? and a = #AValue#} {? and ({? b like '%' + #input# + '%'} {? or c = #input#})}