繁体   English   中英

获得所有perl regex捕获组的价值

[英]get value of all perl regex capture groups

问题:我正在编码一个库,该库接收用户提供的正则表达式,其中包含未知数量的捕获组要针对其他输入运行,并且我想提取以一个字符串连接的所有捕获组的值(以便在其他地方进行进一步处理)。

如果事先知道捕获组的数量,这很简单,因为我只是指定了它们:

#!/usr/bin/perl -w
my $input = `seq -s" " 100 200`;
my $user_regex = 
 qr/100(.*)103(.*)107(.*)109(.*)111(.*)113(.*)116(.*)120(.*)133(.*)140(.*)145/;

if ($input =~ $user_regex)  { print "$1 $2 $3 $4 $5 $6 $7 $8 $9 $10\n"; }

正确产生(忽略多余的空格):

 101 102   104 105 106   108   110   112   114 115   117 118 119 
 121 122 123 124 125 126 127 128 129 130 131 132   
 134 135 136 137 138 139   141 142 143 144

但是,如果捕获组超过10个,并且不修改代码,则会丢失数据。 由于捕获组的数量是未知的,因此目前我在no warnings下进行了数百次手动指定的匹配(“ $ 1”至“ $ 200”),并希望它足够,但是它似乎并不干净健壮。

理想情况下,我希望对命名捕获组执行的操作类似于values %+ ,但对于未命名捕获组则适用。 在perl 5.24中可以吗? 还是建议您采用哪种不太复杂的方法来检索所有已编号捕获组的内容?

也许您可以捕获到一个数组中?

my @captured = $input =~ $user_regexp;
if( @captured ) { print join " ", @captured; print "\n"; }

如果绝对必须使用编号的捕获变量,请使用eval:

my $input = "abc";
my $re = qr/(.)(.)(.)/;
if( $input =~ $re){
  my $num = 1;
  print "captured \$$num = ". eval("\$$num") ."\n" and $num++
    while eval "defined \$$num";
}

要不就:

my $input = "abc";
my $re = qr/(.)(.)(.)/;
if( $input =~ $re){
  my $num = 1;
  print "captured \$$num = $$num\n" and $num++ while defined $$num;
}

...但是最后一个带有标量引用的示例在use strict下不起作用。

如果您正在运行Perl v5.26.2(当前是最新版本)或更高版本,则可以使用内置数组@{^CAPTURE}而不是自己访问捕获变量。

就像普通数组一样,捕获数量为scalar @{^CAPTURE} ,索引从零到$#{^CAPTURE}

请注意,数组是由最近一次成功的模式匹配填充的,因此,就像捕获变量本身一样,您应该在使用@{^CAPTURE}的内容之前检查模式匹配的状态

对于v5.24,没有所有捕获值的数组,但是您可以使用每个匹配项的开始/结束位置提取它们:

my $s  = <some string>;
my $re = <some regex with captures>;
my @matches;
if ($s =~ $re) {
    for my $i (0 .. $#-) {
        push @matches, substr($s, $-[$i], $+[$i] - $-[$i]);
    }
}

在Perlvar- http: //perldoc.perl.org/perlvar.html#Variables-related-to-regular-expressions中,一起记录了Michael CarmanBorodin提到的变量。

就是说,我将几个帖子中的想法组合成一个更全面的答案:

#!/usr/bin/env perl

use Modern::Perl;

my @a = 'abcde' =~ /(.).(.).(.)/;

say do { # map probably creates a temp anonymous array of capture strings
    no strict 'refs';
    join ' ', map { "$$_" } 1..$#-
};

say do { # no copy to array but eval
    eval '"' . join(" ", map { "\$$_" } 1..$#-) . '"';
};

say "@a"; # still not clear from OP why this wasn't the answer

您可以将$ 1 $ 2等中的数字视为变量

$t="abcdefghijklmnop"; 
$t=~/(.)(.)(.)(.)(.)(.)(.)/; 
print $$_ for 1..10;

您可以绕过严格,

  use strict;
  $t="abcdefghijklmnop"; 
  $t=~/(.)(.)(.)(.)(.)(.)(.)/; 
{
    no strict;
    print $$_ for 1..10;
}

或者,您可以将它们放在一个数组中(取自http://perldoc.perl.org/perlre.html

use strict; 
my $t="abcdefghijklmnop"; 
my @a=$t=~/(.)(.)(.)(.)(.)(.)(.)/; 
print "@a";

尽管都不完美,但是使用严格的引用意味着您已经知道变量的名称。 因此,理想情况下,您知道变量名,例如,使用了多少个捕获组

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM