为什么正则表达式捕获组在分配给标量变量时不会返回捕获的文本?

时间:2014-01-14 14:57:19

标签: regex perl capturing-group

我想捕获文件某些行中包含的数字。我正在使用Perl,我正在使用匹配运算符来捕获相对于文件行中其他符号在特定位置发生的数字。这是一个示例行:

fixedStep chrom=chr1 start=3000306 step=1

以下是该脚本的相关部分:

while ( <FILE> ) {
        if ( $_=~m/fixedStep/ ) {
             my $line = $_;
             print $line;
             my $position = ($line =~ /start\=(\d+)/);

             print "position is $position\n\n";

}

$position打印为1,而不是我需要的数字。根据在线正则表达式工具regex101.com,我正在使用的正则表达式工作;它捕获了该行中的相应元素。

3 个答案:

答案 0 :(得分:6)

要从匹配中获取捕获组,您必须在列表 context 中调用它。它可以通过将赋值运算符左侧的标量括在括号中来打开:

my ($position) = $line =~ /start=(\d+)/;

请注意,=在正则表达式中并不特殊,因此无需反斜杠。如果你的输入是unicode,也要小心\d - 你可能不想匹配非阿拉伯语digits(如四或五)。

答案 1 :(得分:4)

当您使用my $position = ($line =~ /start\=(\d+)/);时,由于LHS上的标量赋值,您正在评估标量上下文中的匹配。在标量上下文中,您将获得$position中匹配操作生成的列表大小,该列表将是01,具体取决于此特定匹配是否成功。< / p>

通过在LHS上使用my ($position) =,您可以创建列表上下文。 The successful matched substring ends up in $position(如果有更多,则会被丢弃)。

此外,一般,请避免使用FILE之类的裸字文件句柄(DATAARGV等特殊内置文件除外)。这些是包级变量。另外,在尽可能小的范围内分配一个词法变量,而不是覆盖$_。此外,可以组合测试和匹配,从而产生您想要匹配的字符串的更具体的规范。当然,您最了解约束,因此,例如,如果chrom字段在有效输入中始终显示为第二个,则应指定该值。

下面的模式只要求行以fixedStep开头,并且在您要捕获的行之前还有一个字段。

#!/usr/bin/env perl

use strict;
use warnings;

while (my $line = <DATA>) {
    if (my ($position) = ($line =~ m{
        \A
        fixedStep
        \s+ \S+ \s+
        start=([0-9]+)
    }x)) {
        print "$position\n";
    }
}

__DATA__
fixedStep chrom=chr1 start=0 step=1
fixedStep chrom=chr1 start=3000306 step=1
start=9999 -- hey, that's wrong

输出:

C:\Temp> tt
0
3000306

答案 2 :(得分:1)

[编辑:请参阅评论,了解有关原文出错的原因]

您可以使用

my ($position) = ($line =~ /start\=(\d+)/);

<德尔>或

<德尔> my $position = $line =~ /start\=(\d+)/;

要么应该工作

否则,你是混合列表和标量上下文,而随后只是得到列表的长度