Perl $ 1给出未初始化的值错误

时间:2014-06-24 15:23:49

标签: perl

我正在尝试提取字符串的一部分并将其放入一个新变量中。我正在看的字符串是:

maker-scaffold_26653|ref0016423-snap-gene-0.1

(在$gene_name变量内)

我想要匹配的是:

scaffold_26653|ref0016423

我正在使用以下代码:

my $gene_name;
my $scaffold_name;
if ($gene_name =~ m/scaffold_[0-9]+\|ref[0-9]+/) { 
    $scaffold_name = $1;
    print "$scaffold_name\n";
}

尝试执行时出现以下错误:

Use of uninitialized value $scaffold_name in concatenation (.) or string

我知道模式是正确的,因为如果我使用$'代替$1,我会得到

-snap-gene-0.1

我有点失落:为什么$1不能在这里工作?

2 个答案:

答案 0 :(得分:4)

如果你想使用匹配中的值,你必须在正则表达式中使用()字符

答案 1 :(得分:3)

要扩展Jens的答案,正则表达式中的()表示匿名捕获组。捕获组中匹配的内容从左到右存储在$ 1-9 +中,例如,

/(..):(..):(..)/
在HH上:MM:SS时间字符串将分别以1美元,2美元,3美元存储小时,分钟和秒。当然,这开始变得笨拙并且不是自我记录的,因此您可以将结果分配到列表中:

my ($hours, $mins, $secs) = $time =~ m/(..):(..):(..)/;

因此,您的示例可以通过直接赋值绕过$ variables的使用:

my ($scaffold_name) = $gene_name =~ m/(scaffold_[0-9]+[|]ref[0-9]+)/;
# $scaffold_name now contains 'scaffold_26653|ref0016423'

你甚至可以通过使用for作为一个局部化器来摆脱丑陋的=〜绑定:

my $scaffold_name;
for ($gene_name) {
    ($scaffold_name) = m/(scaffold_\d+[|]ref\d+)/;
    print $scaffold_name;
}

如果事情开始变得更复杂,我更喜欢使用命名捕获组(在Perl v5.10.0中引入):

$gene_name =~ m{
    (?<scaffold_name> # ?<name> creates a named capture group
        scaffold_\d+?  # 'scaffold' and its trailing digits
        [|]            # Literal pipe symbol
        ref\d+         # 'ref' and its trailing digits
    )
}xms; # The x flag lets us write more readable regexes
print $+{scaffold_name}, "\n";

命名捕获组的结果存储在魔术哈希%+中。访问与任何其他哈希查找一样,捕获组作为键。 %+在本地作用域的方式与$相同,因此在大多数情况下它可以用作替代它们。

对于这个特定的例子来说这太过分了,但是随着正则表达式开始变得越来越大,越来越复杂,这就省去了你必须一直向后滚动并从左到右计算匿名捕获组以找到其中哪一个的麻烦darn $ variables持有您想要的捕获,或扫描长列表分配以找到添加新变量的位置以保存插入到中间的捕获。

我个人的经验法则是将捕获的匿名结果分配给3个或更少捕获的描述性词汇范围变量,然后在需要更多时使用正则表达式中的命名捕获,注释和缩进。