【问题标题】:Matching balanced parenthesis in Perl regex在 Perl 正则表达式中匹配平衡括号
【发布时间】:2011-12-19 22:04:42
【问题描述】:

我有一个表达式需要拆分并存储在一个数组中:

aaa="bbb{ccc}ddd" { aa="bb,cc" { a="b", c="d" } }, aaa="bbb{}" { aa="b}b" }, aaa="bbb,ccc"

一旦拆分并存储在数组中,它应该看起来像这样:

aaa="bbb{ccc}ddd" { aa="bb,cc" { a="b", c="d" } }
aaa="bbb{}" { aa="b}b" }
aaa="bbb,ccc"

我使用 Perl 5.8 版,有人可以解决这个问题吗?

【问题讨论】:

    标签: regex perl perl5.8


    【解决方案1】:

    使用 perl 模块“Regexp::Common”。它有一个很好的平衡括号正则表达式,效果很好。

    # ASN.1
    use Regexp::Common;
    $bp = $RE{balanced}{-parens=>'{}'};
    @genes = $l =~ /($bp)/g;
    

    【讨论】:

      【解决方案2】:

      perlre 中有一个示例,使用了 v5.10 中引入的递归正则表达式功能。尽管您仅限于 v5.8,但其他提出此问题的人应该得到正确的解决方案:)

      $re = qr{ 
                  (                                # paren group 1 (full function)
                      foo
                      (                            # paren group 2 (parens)
                          \(
                              (                    # paren group 3 (contents of parens)
                                  (?:
                                      (?> [^()]+ ) # Non-parens without backtracking
                                      |
                                      (?2)         # Recurse to start of paren group 2
                                  )*
                              )
                          \)
                      )
                  )
          }x;
      

      【讨论】:

        【解决方案3】:

        我或多或少同意 Scott Rippey 关于编写自己的解析器的观点。这是一个简单的:

        my $in = 'aaa="bbb{ccc}ddd" { aa="bb,cc" { a="b", c="d" } }, ' .
                 'aaa="bbb{}" { aa="b}b" }, ' .
                 'aaa="bbb,ccc"'
        ;
        
        my @out = ('');
        
        my $nesting = 0;
        while($in !~ m/\G$/cg)
        {
          if($nesting == 0 && $in =~ m/\G,\s*/cg)
          {
            push @out, '';
            next;
          }
          if($in =~ m/\G(\{+)/cg)
            { $nesting += length $1; }
          elsif($in =~ m/\G(\}+)/cg)
          {
            $nesting -= length $1;
            die if $nesting < 0;
          }
          elsif($in =~ m/\G((?:[^{}"]|"[^"]*")+)/cg)
            { }
          else
            { die; }
          $out[-1] .= $1;
        }
        

        (在 Perl 5.10 中测试;抱歉,我手边没有 Perl 5.8,但据我所知没有任何相关差异。)不用说,您需要替换 dies具有特定于应用程序的东西。而且您可能必须调整上述内容以处理示例中未包含的情况。 (例如,带引号的字符串是否可以包含\"?可以使用' 代替"吗?这段代码不能处理这两种可能性。)

        【讨论】:

        • 我很高兴知道一个讲 Perl 的人同意我的回答......我只会说 PCRE,所以我的回答大胆假设解析器比可能不可能的正则表达式更容易。
        • 我在这里看不到任何会阻止它在 Perl5 版本 8 上工作的东西
        【解决方案4】:

        为了匹配平衡括号或花括号,并且如果您想考虑反斜杠(转义),建议的解决方案将不起作用。相反,你会写这样的东西(基于perlre 中建议的解决方案):

        $re = qr/
        (                                                # paren group 1 (full function)
            foo
            (?<paren_group>                              # paren group 2 (parens)
                \(
                    (                                    # paren group 3 (contents of parens)
                        (?:
                            (?> (?:\\[()]|(?![()]).)+ )  # escaped parens or no parens
                            |
                            (?&paren_group)              # Recurse to named capture group
                        )*
                    )
                \)
            )
        )
        /x;
        

        【讨论】:

          【解决方案5】:

          试试这样的:

          use strict;
          use warnings;
          use Data::Dumper;
          
          my $exp=<<END;
          aaa="bbb{ccc}ddd" { aa="bb,cc" { a="b", c="d" } }     , aaa="bbb{}" { aa="b}b" }, aaa="bbb,ccc"
          END
          
          chomp $exp;
          my @arr = map { $_ =~ s/^\s*//; $_ =~ s/\s* $//; "$_}"} split('}\s*,',$exp);
          print Dumper(\@arr);
          

          【讨论】:

          • 感谢您的回复。我发现匹配 aa="bb},cc" 之类的东西时它会中断。
          【解决方案6】:

          虽然Recursive Regular Expressions 通常可用于捕获“平衡括号”{},但它们对您不起作用,因为您还需要匹配“平衡引号”"
          对于 Perl 正则表达式来说,这将是一项非常棘手的任务,我相当肯定这是不可能的。 (相比之下,它可能可以通过Microsoft's "balancing groups" Regex feature 完成。

          我建议创建您自己的解析器。在处理每个字符时,您计算每个 "{},并且仅在 ,“平衡”时拆分它们。

          【讨论】:

          • 我认为它可以在 Perl 中完成,只是不容易。特别是对于新的 Perl 程序员。尽管使用Regexp::Grammars 样式的正则表达式可能更容易。使用 real 解析器会更好,Marpa 可能。
          • 5.8 不支持 Regexp::Grammars :(
          • 这很有可能,但我不建议这样做。 :)
          猜你喜欢
          • 2010-10-07
          • 2011-09-13
          • 2015-11-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多