正则表达式匹配括号
匹配对称的括号
Matching Balanced Sets of Parentheses
对称的圆括号、⽅括号之类的符号匹配起来⾮常⿇烦。在处理配置⽂件和源代码时,经常需要匹配对称的括号。例如,解析C语⾔代码时可能需要处理某个函数的所有参数。函数的参数包含在函数名称之后的括号⾥,⽽这些参数本⾝⼜有可能包含嵌套的函数调⽤或是算式中的括号。我们先不考虑嵌套的括号,你或许会想到「\bfoo\([^])*\」,但这⾏不通。正则表达式获取括号内容
秉承C的光荣传统,我把⽰范函数命名为foo。表达式中的标记部分是⽤来捕获参数的。对于foo(2, 4.0)和foo(somevar, 3.7)之类的参数,这个表达式完全没问题。但是,它也可以匹配foo(bar(somevar), 3.7),这可不是我们需要的。所以要⽤到⽐「[^)]*」更聪明的办法。
为了匹配括号部分,我们可以尝试下⾯的这些正则表达式:
1. \(.*\) 括号及括号内部的任何字符。
2. \([^)]*\) 从⼀个开括号到最近的闭括号。
3. \([^()]*\) 从⼀个开括号到最近的闭括号,但是不容许其中包含开括号。
图5-1显⽰了对⼀⾏简单代码应⽤这些表达式的结果。
图5-1:三个表达式的匹配位置
我们看到,第⼀个正则表达式匹配的内容太多(注2),第⼆个正则表达式匹配的内容太少,第三个正则表达式⽆法匹配。孤⽴地看,第三个正则表达式能够匹配‘(this)’,但是因为表达式要求它必须紧接在foo之后,所以⽆法匹配。所以,这三个表达式都不合格。
真正的问题在于,⼤多数系统中,正则表达式⽆法匹配任意深度的嵌套结构。在很长的时间内,这是放之四海⽽皆准的规则,但是现在Perl、.NET和PCRE/PHP都提供了解决的办法(参见第328、436、475页)。但是,即使不⽤这些功能,我们也可以⽤正则表达式来匹配特定深度的嵌套括号,但不是任意深度的嵌套括号。处理单层嵌套的正则表达式是:
「\[^()]*(\([^()]*\)[^()]*)*\)」
这样类推下去,更深层次的嵌套就复杂得可怕。但是,下⾯的Perl程序,在指定嵌套深度$depth之后,⽣成的正则表达式可以匹配最⼤深度为$depth的嵌套括号。它使⽤的是Perl的“string x count”运算符,这个运算符会把string重复count次:
$regex = '\('.'(?:[^()]|\(' x $depth . '[^()]*' . '\))*' x $depth .'\)';
这个表达式留给读者分析。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论