使用像perl这样的递归正则表达式匹配Ruby中的平衡括号

我一直在寻找一种方法来匹配正则表达式中的平衡括号,并在Perl中找到了一种使用递归正则表达式的方法:

my $re; $re = qr{ \( (?: (?> [^()]+ ) # Non-parens without backtracking | (??{ $re }) # Group with matching parens )* \) }x; 

来自perl正则表达式网站 。

有没有办法在Ruby或类似语言中执行此操作?

更新

对于那些感兴趣的人有一些有趣的链接:

Oniguruma手册 – 来自Sawa的回答。

实用程序员的Ruby 1.9正则表达式示例章节

是。 使用oniguruma regex引擎,它可以在Ruby 1.9中内置,并且可以在Ruby 1.8上安装,你可以做到这一点。 您使用(?...)(?'name'...) 。 然后在同一个正则表达式中使用\g\g'name'调用subregex。 所以你的正则表达式转换为oniguruma正则表达式将是:

 re = %r{ (? \( (?: (?> [^()]+ ) | \g )* \) ) }x 

另请注意,PHP> = 5的多字节字符串模块使用oniguruma regex引擎,因此您将能够执行相同的操作。

oniguruma手册在这里 。

我喜欢上面的解决方案,但经常有人希望忽略转义字符。 假设\转义后续字符,以下正则表达式也处理转义字符。

 ESC= /(?[\\](?:[\\][\\])*)/ UNESC= /(?:\A|(?<=[^\\]))(?:[\\][\\])*/ BALANCED_PARENS = /#{UNESC}( (?\( (?> (?> (?:#{ESC}\(|#{ESC}\)|[^()])+ ) |\g )* \)) ) /xm 

鉴于负面观察的局限性,由匹配的parens划分的部分将是第一次捕获而不是整个匹配(整个匹配可能包含前导逃逸的反斜杠)。

ESC和UNESC复杂性的原因是假设\\是逃避反斜杠。 我们只在初始paren匹配之前使用UNESC序列,因为任何其他转义括号将在primefaces组内匹配并且永远不会回溯。 实际上,如果我们尝试将UNESC前缀用于内部或最终的匹配,当primefaces组内的[^()]与前导匹配并且拒绝回溯时,它将失败。

这个正则表达式将扫描第一个限定有效平衡括号的paren。 因此,给定字符串“((stuff)”它将匹配“(stuff)”。通常,期望的行为是定位第一个(未转义的)括号并且匹配内部(如果是平衡的)或者不匹配。不幸的是,primefaces分组不会阻止整个正则表达式退出,并且稍后会尝试匹配,因此我们必须在字符串的开头锚定并仅查看第一次捕获。以下正则表达式进行此更改:

 BALANCED_PARENS = /\A(?:#{ESC}\(|#{ESC}\)|[^()])*+ (?\( (? (?> (?> (?:#{ESC}\(|#{ESC}\)|[^()])+ ) |\(\g )* \)) ) /xm