问题:我正在编写一个接收用户提供的正则表达式的库,该正则表达式包含要针对其他输入运行的未知数量的捕获组,我想提取在一个字符串中连接的所有捕获组的值(以进一步处理其他地方)。
如果预先知道捕获组的数量,这是微不足道的,因为我只是指定它们:
#!/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
pragma下使用了数百个手动指定的匹配(" $ 1"到" $ 200")并希望它是足够了,但它看起来并不特别干净或健壮。
理想情况下,我喜欢像values %+
那样对命名捕获组有效的东西,但对于非命名捕获组。 perl 5.24有可能吗?或者,您建议在检索所有编号捕获组的内容时采用哪种方法?
答案 0 :(得分:4)
也许你可以捕捉到一个阵列?
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
下无效。
答案 1 :(得分:2)
如果您运行的是Perl v5.26.2(当前是最新版本)或更高版本,那么您可以使用内置数组@{^CAPTURE}
而不是自己访问捕获变量
就像普通数组一样,捕获次数为scalar @{^CAPTURE}
,索引从零到$#{^CAPTURE}
请注意,数组由最新的成功模式匹配填充,因此就像捕获变量本身一样,您应该在使用@{^CAPTURE}
的内容之前检查模式匹配的状态。
答案 2 :(得分:1)
对于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]);
}
}
答案 3 :(得分:0)
Michael Carman和Borodin提到的变量在perlvar中有用地记录在一起 - http://perldoc.perl.org/perlvar.html#Variables-related-to-regular-expressions。
那就是说我把几个帖子的想法结合到了我希望的更全面的答案中:
#!/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
答案 4 :(得分:-1)
您可以将$ 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";
虽然两者都不完美,但使用严格引用意味着您知道变量的名称。因此,理想情况下,您知道变量名称,例如,您使用了多少个捕获组