匹配Perl正则表达式中的平衡括号

时间:2011-11-01 23:18:47

标签: regex perl perl5.8

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

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,有人可以解决这个问题吗?

7 个答案:

答案 0 :(得分:9)

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

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

答案 1 :(得分:6)

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;

答案 2 :(得分:1)

尝试这样的事情:

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);

答案 3 :(得分:1)

我或多或少同意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,但据我所知,没有任何相关的差异。)不用说,你会想要替换{{1}用特定于应用程序的东西。而且您可能需要调整上述内容来处理示例中未包含的案例。 (例如,引用的字符串可以包含die吗?可以使用\"代替'吗?此代码无法处理这两种可能性。)

答案 4 :(得分:1)

要匹配平衡括号或大括号,并且如果您想考虑反斜杠(转义),则建议的解决方案将不起作用。相反,您可以编写如下内容(以 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 :(得分:0)

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

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

答案 6 :(得分:-1)

拆分解决方案似乎最简单。在主要变量aaa的前瞻中拆分,并使用单词边界。使用可选字符组删除尾随空格和逗号。

$string = 'aaa="bbb{ccc}ddd" { aa="bb,cc" { a="b", c="d" } }, aaa="bbb{}" { aa="b}b" }, aaa="bbb,ccc"';
my @array = split /[,\s]*(?=\baaa\b)/, $string;