-
如何匹配对称的括号,且允许单层嵌套 ?
- 就像匹配一个允许包含转义字符的字符串一样,
"[^\\"]*(\\.[^\\"]*)*"
,这是我们常用的一种正则结构 Unrolling the Loop,即opening normal* (special normal*)* closing
;类似的,我们可以很容易地构造出匹配允许单层嵌套的对称括号的正则表达式:\([^()]*(\([^()]*\)[^()]*)*\)
。
- 就像匹配一个允许包含转义字符的字符串一样,
-
以
perl
程序为例,如何指定允许嵌套的深度$depth
?-
实际上,若已有匹配括号文本的正则表达式
\([^()]*\)
,其不允许嵌套;那么用递归的思想,则有\(([^()]|\([^()]*\))*\)
,此正则表达式也可以用来匹配允许单层嵌套的对称括号。为了便于阅读,书写如下:my $Level0 = qr/ \( [^()]* \) /x; # Parenthesized text my $Level1 = qr/ \( ([^()] | $Level0 )* \) /x; # One level of nesting my $Level2 = qr/ \( ([^()] | $Level1 )* \) /x; # Two levels of nesting my $Level3 = qr/ \( ([^()] | $Level2 )* \) /x; # Three levels of nesting my $Level4 = qr/ \( ([^()] | $Level3 )* \) /x; # Four levels of nesting my $Level5 = qr/ \( ([^()] | $Level4 )* \) /x; # Five levels of nesting
-
对此归纳一下,我们便可以得到允许指定嵌套深度
$depth
的正则表达式:$regex = '\(' . '(?:[^()]|\(' x $depth . '[^()]*' . '\))*' x $depth . '\)';
-
-
如何匹配允许嵌套任意深度的对称括号 ?
- 依据上述,若正则表达式支持递归结构
(?R)
,则\((?:[^()]|(?R))*\)
便可以用来递归匹配允许嵌套任意深度的对称括号;我们也可以把开头和结尾的\(
和\)
移动到递归结构(?R)
的两端,即(?:[^()]|\((?R)\))*
,这样,正则表达式就会变得十分灵活,因为它不包含外部的\(
和\)
,所以在任何可能出现嵌套括号的地方都能使用。 - 实际案例,例如 Stack Overflow Answer,提问者想匹配
pow(var,2)
,但是var
表达式中还可能嵌套任意深度的对称括号:先添加外部的opening
和closing
,即pow\s*\(
和,\s*2\s*\)
,然后用我们的(?:[^()]|\((?R)\))*
来填充var
部分即可;此时不能再用(?R)
来递归引用整个正则表达式,我们需要添加括号来捕获组,并将(?R)
修改为相应的捕获 ID,即((?:[^()]|\((?1)\))*)
;完整的正则表达式为:pow\s*\(((?:[^()]|\((?1)\))*),\s*2\s*\)
。
- 依据上述,若正则表达式支持递归结构
相似的问题:Regular expression to match balanced parentheses、PHP \[(?:[^][]|(?R))*\]
;然而事实上,大多数的正则方言都不支持递归匹配,如 .NET (?R)
& Balancing Group,若不使用平衡组/递归匹配可以参考 Match nested brackets with regex without using recursion or balancing groups,或者你可以编写一段程序来实现相同的功能。
Reference:
- 《Mastering Regular Expressions, 3rd Edition》
- Stack Overflow: What does this regex mean? [FAQ]