版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433629
有时候,我们需要用正则表达式来分析一个计算式中的符号配对情况。比如,使用表达式 “( [^)]* )
” 或者 “( .*? )
” 可以匹配一对小括号。但是如果括号内还嵌有一层或多层括号的话(如 “(() ( ) )
“),则这种写法将不能够匹配正确 。
再比如,java代码中一个函数/方法都是由嵌套的{}
构成的,如何准确的从源码文件中找出一个方法也需要对{}
递归匹配或叫嵌套匹配。
目前并不是所有的正则表达式引擎都具备了递归匹配功能,根据网上的一些资料得到的信息是目前只有Perl,PHP,GRETA,还有.Net Framework提供了此项功能。
对Perl等还不了解,本文关注的是.Net Framework正则表达引擎来实现符号的递归匹配。
在.Net Framework中这个特性是由《平衡组定义》来实现的。
如下一个简单的例子(来自于Microsoft的《分组构造》),用于()
的递归匹配
(((?'Open'()[^()]*) ((?'Close-Open'))[^()]*) )*(?(Open)(?!))$
匹配“3 2^((1-3)*(3-1))”中的“((1-3)*(3-1))”
如果要匹配java代码中的一个方法。。。上面的表达式要稍微修改下。
比如要匹配代码中所有的有@Override
注释的方法,可以写成这样:
@Override[^{}] {[^{}]*(((?'Open'{)[^{}]*) ((?'Close-Open'})[^{}]*) )*(?(Open)(?!))[nrt ]*}
下图是显示的匹配结果
表达式中[^{}]*(((?'Open'{)[^{}]*) ((?'Close-Open'})[^{}]*) )*(?(Open)(?!))
部分用于匹配最外层{}
号内的所有{}
嵌套。
掌握了这个方法后,我们可以进一步匹配代码中所有的有@Override
注释的泛型方法
表达式更复杂一些:
代码语言:javascript复制@Override[nrt ]*[^{}]*<[^<>]*(((?'Open'<)[^<>]*) ((?'Close-Open'>)[^<>]*) )*(?(Open)(?!))[nrt ]*>[^{}] {[^{}]*(((?'Open'{)[^{}]*) ((?'Close-Open'})[^{}]*) )*(?(Open)(?!))[nrt ]*}
下图是显示的匹配结果
表达式中<[^<>]*(((?'Open'<)[^<>]*) ((?'Close-Open'>)[^<>]*) )*(?(Open)(?!))[nrt ]*>
部分用于匹配匹配最外层<>
号以及内部的所有<>
嵌套,这样,不仅可以适应<T1,T2>
这样的单层<>
号,还可以用于<T1,List<T2>>
这种复杂类型的泛型方法定义
注意:
关于在源码中嵌套匹配{}
,这个表达其实是有隐含缺陷的:如果""
字符串中包含了不匹配的{}
,这个表达式是无法匹配的。
参考资料:
《平衡组定义》https://msdn.microsoft.com/zh-cn/library/bs2twtah.aspx#balancing_group_definition
《分组构造》https://msdn.microsoft.com/zh-cn/library/az24scfc.aspx#grouping_constructs