1

我想捕获文件某些行中包含的数字。我正在使用 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,我使用的正则表达式有效;它捕获行中的适当元素。

4

3 回答 3

6

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

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

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

于 2014-01-14T15:09:01.960 回答
4

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

通过my ($position) =在 LHS 上使用,您可以创建列表上下文。成功匹配的子字符串最终会出现$position(如果有更多,它们会被丢弃)。

此外,一般来说,避免使用裸字文件句柄,例如FILE(除了特殊的内置文件句柄,例如DATAand ARGV)。这些是包级别的变量。此外,在尽可能小的范围内分配给词法变量,而不是覆盖$_. 此外,可以将测试和匹配结合起来,从而对要匹配的字符串进行更具体的规范。当然,您最了解约束条件,因此,例如,如果该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:\温度> tt
0
3000306
于 2014-01-14T15:08:41.273 回答
1

[编辑:请参阅评论以解释为什么敲击文本是错误的]

您可以使用

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

或者

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

要么应该工作

否则,您正在混合列表和标量上下文, 和随后只是获得列表的长度

于 2014-01-14T15:01:08.607 回答