【问题标题】:Matching n parentheses in perl regex在 perl 正则表达式中匹配 n 个括号
【发布时间】:2010-06-17 22:32:10
【问题描述】:

我有一些要在 Perl 中解析的数据,并且会在不久的将来添加越来越多不同格式的数据。我想做的是编写一个易于使用的函数,我可以将一个字符串和一个正则表达式传递给它,它会返回括号中的任何内容。它会像这样工作(伪代码):

sub parse {
  $data = shift;
  $regex = shift;

  $data =~ eval ("m/$regex/")
  foreach $x ($1...$n)
  {
    push (@ra, $x); 
  }
  return \@ra;
}

那么,我可以这样称呼它:

@subs = parse ($data, '^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)');

如您所见,此代码存在一些问题。我不知道 eval 是否可以工作,'foreach' 肯定不会工作,而且不知道有多少括号,我不知道循环多少次。

这对于拆分来说太复杂了,所以如果我忽略了其他功能或可能性,请告诉我。

感谢您的帮助!

【问题讨论】:

    标签: regex perl eval subroutine


    【解决方案1】:

    在列表上下文中,正则表达式将返回所有带括号的匹配项的列表。

    所以你要做的就是:

    my @matches = $string =~ /regex (with) (parens)/;
    

    假设它匹配,@matches 将是两个捕获组的数组。

    所以使用你的正则表达式:

    my @subs = $data =~ /^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)/;
    

    另外,当你有很长的正则表达式时,Perl 有x 修饰符,它位于结束正则表达式分隔符之后。 x 修饰符允许您在正则表达式中放置空格和换行符以提高可读性。

    如果您担心捕获组的长度可能为零,您可以通过@subs = grep {length} @subs 传递匹配项以过滤掉它们。

    【讨论】:

    • 如果您不知道正则表达式是否有括号,并且如果没有则不返回任何内容(而不是默认的整个匹配字符串),请添加一个额外的集合:$string =~ /(regex)/ 和从结果中丢弃它。
    • 该 grep 将过滤掉匹配中未实际使用的括号,但不会过滤掉零长度的括号(将被定义和“”)
    • 谢谢!我从事 Perl 多年,我怎么不知道可以在列表上下文中返回匹配项?可能不得不回去重新阅读我的书。
    【解决方案2】:

    那么,我可以这样称呼它:

    @subs = parse($data, 
              '^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)');
    

    改为:

    parse($data, 
        qr/^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)/);
    

    此外,如果您可以使用named captures(即 Perl 5.10 及更高版本),您的任务将会变得更简单。这是一个例子:

    #!/usr/bin/perl
    
    use strict; use warnings;
    
    my %re = (
        id => '(?<id> [0-9]+ )',
        name => '(?<name> \w+ )',
        value => '(?<value> [0-9]+ )',
    );
    
    my @this = (
        '123,one:12',
        '456,two:21',
    );
    
    my @that = (
        'one:[12],123',
        'two:[21],456',
    );
    
    my $this_re = qr/$re{id}   ,   $re{name}    : $re{value}/x;
    my $that_re = qr/$re{name} : \[$re{value}\] , $re{id}   /x;
    
    use YAML;
    
    for my $d ( @this ) {
        print Dump [ parse($d, $this_re) ];
    }
    
    for my $d ( @that ) {
        print Dump [ parse($d, $that_re) ];
    }
    
    sub parse {
        my ($d, $re) = @_;
        return unless $d =~ $re;
        return my @result = @+{qw(id name value)};
    }
    

    输出:

    --- - 123 - 一 - 12 --- - 456 - 二 - 21 --- - 123 - 一 - 12 --- - 456 - 二 - 21

    【讨论】:

      【解决方案3】:

      您正在尝试使用正则表达式解析复杂的表达式 - 这对于这项工作来说是一个不足的工具。回想一下,正则表达式不能解析高级语法。出于直觉,任何可能嵌套的表达式都不能用正则表达式解析。

      【讨论】:

      • perl 的正则表达式不规则。你可以使用(??{blah}),虽然这不是完全推荐的做法。
      • perl 的正则表达式引擎也支持递归,这使得它可以轻松匹配嵌套结构
      • True - 许多正则表达式实现实际上可以解析比常规语言集更多的内容,但这并不一致。如果您需要解析语法 - 请使用适当的语法解析器。
      【解决方案4】:

      当你想在括号内查找文本时,你想使用Text::Balanced

      但是,那不是你想要做的,所以它对你没有帮助。

      【讨论】:

      • 尽管有问题的名称,但似乎 OP 实际上并不希望匹配嵌套的括号,只是为了使用可能具有任意数量的连续捕获组的正则表达式
      • 抱歉,我应该说“括号分组”而不是“括号”。
      猜你喜欢
      • 2011-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多