正则表达式匹配受保护的分隔值

时间:2012-07-27 07:17:10

标签: regex perl

我想要一个正则表达式来匹配分隔值和一些可以包含分隔符的受保护值。

例如:

"A,B,{C,D,E},F"

会给:

  • “A”
  • “B”
  • “{C,d,E}”
  • “F”

请注意,受保护的值可以嵌套,如下所示:

"A,B,{C,D,{E,F}},G"

会给:

  • “A”
  • “B”
  • “{C,d,{E,F}}”
  • “G”

我已经使用字符迭代编写了该功能,如下所示:

sub Parse
{
  my @item;

  my $curly;
  my $string;
  foreach(split //)
  {
    $_ eq "{" and ++$curly;
    $_ eq "}" and --$curly;

    if(!$curly && /[,:]/)
    {
      push @item, $string;
      undef $string;
      next;
    }
    $string .= $_;
  }

  push @item, $string;
  return @item;
}

但是,正则表达式确实会更加出色。

6 个答案:

答案 0 :(得分:2)

支持嵌套的正则表达式如下所示:

my @items;
push @items, $1 while
   /
      (?: ^ | \G , )
      (
         (?: [^,{}]+
         |   (
                \{
                   (?: [^{}]
                   |   (?2)
                   )*
                \}
             )
         |   # Empty
         )
      )
   /xg;

$ perl -E'$_ = shift; ... say for @items;' 'A,B,{C,D,{E,F}},G'
A
B
{C,D,{E,F}}
G

假设有效输入,因为它无法同时提取和验证。 (好吧,并非没有让事情变得非常混乱。)

答案 1 :(得分:1)

$a = "A,B,{C,D,E},F";
while ($a =~ s/(\{[\{\}\w,]+\}|\w)//) {
    push (@res, $1);
}
print "\@res: @res\n"

结果:

@res: A B {C,D,E} F

说明:我们尝试在循环中连续匹配受保护的块\{[\{\}\w,]+\}或单个字符\w,如果匹配则从原始字符串中删除它。每次匹配时,我们都会将它(意思是$1)存储在数组中,etvoilà!

答案 2 :(得分:1)

改进了nhahtdh的回答。

$_ = "A,B,{C,D,E},F";
while ( m/(\{.*?\}|((?<=^)|(?<=,)).(?=,|$))/g ) {
    print "[$&]\n";
}

再次改进它。请看这个!

$_ = "A,B,{C,D,{E,F}},G";
while ( m/(\{.*\}|((?<=^)|(?<=,)).(?=,|$))/g ) {
    print "$&\n";
}

它会得到:

A
B
{C,D,{E,F}}
G

答案 3 :(得分:0)

这是bash中的正则表达式:

chronos@localhost / $ echo "A,B,{C,D,E},F" | grep -oE "(\{[^\}]*\}|[A-Z])"
A
B
{C,D,E}
F

答案 4 :(得分:0)

试试这个正则表达式。使用正则表达式匹配并提取令牌。

/(\{.*?\}|(?<=,|^).*?(?=,|$))/

我没有在Perl中测试过这段代码。

关于正则表达式引擎如何在这里工作的假设(我假设它将尝试匹配第二部分之前的第一部分\{.*?\})。我还假设没有嵌套的花括号和严重配对的花括号。

答案 5 :(得分:-2)

$s = "A,B,{C,D,E},F";
@t = split /,(?=.*{)|,(?!.*})/, $s;