如何匹配平衡的花括号跳过逃脱的?

时间:2015-12-04 16:41:33

标签: regex perl recursion

我正在尝试使用正则表达式来匹配平衡的大括号,这些大括号会考虑并跳过转义大括号。

以下正则表达式不起作用。该脚本打印{ def \}而不是预期的输出:{ def \} hij \\\} klm }。我究竟做错了什么?我该如何改进呢?

my $str = 'abc { def \} hij \\\} klm } nop';

if ( $str =~ m/
              (
                \{
                  (?: \\\\
                  |   \\[\{\}]
                  |   [^\{\}]+
                  |   (?-1)
                  )*
                \}
              )
              /x
) { print $1, "\n" }

2 个答案:

答案 0 :(得分:3)

这里有两个问题 - $str中字符串的值和正则表达式

即使在单引号字符串中,当两个一起出现或者它们作为字符串中的最后一个字符出现时,必须转义反斜杠。一对反斜杠减少为一,因此子串\\\}将在最终字符串中生成\\}。要生成三个反斜杠后跟一个右括号,代码中需要六个反斜杠 - \\\\\\}(尽管有五个反斜杠)

您的正则表达式模式不正确,因为字符类[^{}]也会匹配单个反斜杠,这将阻止它被识别为转义大括号序列的一部分。因此备用[^{}\\]+与字符串中的def \匹配,使}与其反斜杠分离

该程序可以满足您的需求

use strict;
use warnings 'all';

my $str = 'abc { def \} hij \\\\\\} klm } nop';

print $str, "\n";

if ( $str =~ m/
              (
                \{
                  (?:
                  [^{}\\]+  |
                  \\.       |
                  (?-1)
                  )*
                \}
              )
              /xs ) {

    print $1, "\n";
}

输出

abc { def \} hij \\\} klm } nop
{ def \} hij \\\} klm }

答案 1 :(得分:2)

您可以使用支持任何转义符号的以下正则表达式:

(?<=^|\\.|[^\\])({(?>\\.|[^{}]|(?1))*})

带有评论的VERBOSE版本:

(?<=^|\\.|[^\\]) # Before `{` there is either start of string, escaped entity or not a \
(
   {            # Opening {
     (?>        # Start of atomic group
          \\.   # Any escaped symbol 
         |      
          [^{}] # any symbol but `{` and `}`
         | 
          (?1)  # Recurse the first subpattern
     )*         # repeat the atomic group 0 or more times
   }            # closing brace
)

请参阅regex demo

<强>更新

由于上述正则表达式可能会将转义的左括号与第一个字符匹配,因此您可以使用

[^\\{}]*(?:\\.[\\{}]*)*(?<!\\)({(?>\\.|[^{}]|(?1))*})

请参阅regex demo

它将匹配所有转义和不必要的子字符串,并捕获到第1组仅有效的子字符串。