Perl - 哈希的初始化

EA0*_*A00 2 arrays perl hash

我不确定如何正确初始化我的哈希 - 我正在尝试为输入文件中的耦合行中的值创建键/值对.

例如,我的输入如下所示:

@cluster t.18
46421 ../../../output###.txt/
@cluster t.34
41554 ../../../output###.txt/
Run Code Online (Sandbox Code Playgroud)

我从第1行(@cluster行)中提取t数,并将其与第二行中的输出###.txt相匹配(以46421开头的行).但是,我似乎无法使用我编写的脚本将这些值放入哈希.

#!/usr/bin/perl
use warnings;
use strict;

my $key;
my $value;
my %hash;

my $filename = 'input.txt';
open my $fh, '<', $filename or die "Can't open $filename: $!";

while (my $line = <$fh>) {
        chomp $line;
        if ($line =~ m/^\@cluster/) {
            my @fields = split /(\d+)/, $line;
            my $key = $fields[1];          
        }
        elsif ($line =~ m/^(\d+)/) { 
            my @output = split /\//, $line;
            my $value = $output[5];       
}          
        $hash{$key} = $value;
}
Run Code Online (Sandbox Code Playgroud)

zdi*_*dim 7

这是一个好主意,但是你在块中$key创建my的是一个局限于该if 的局部变量,掩​​盖了全局$key.在if块内,符号$key与您提前声明的符号无关.见my in perlsub.

这个本地$key一旦if完成就超出了范围,并且在if块之外不存在.全局在循环中的其他位置可见$key后再次可用if,但由于从未分配过,因此未定义.这同样适用于$valueelsif .

只需将my声明放在循环中,从而分配给那些全局变量(如预期的那样?).所以,$key = ...$value = ...,哈希将被正确分配.


注意 - 这是关于如何正确获得该哈希分配.我不知道您的实际数据是如何看的以及该行是否被正确解析.这是一个玩具input.txt

@cluster t.1 
1111 ../../../output1.1.txt/
@cluster t.2 
2222 ../../../output2.2.txt/

我选择第4个字段而不是第6个字段$value = $output[3];,然后添加

print "$_ => $hash{$_}\n" for keys %hash;
Run Code Online (Sandbox Code Playgroud)

循环之后.这打印

1 => output1.1.txt
2 => output2.2.txt

我不确定这是否是你想要的,但哈希是很好的.


关于解析中工具选择的评论

解析数字的行,通过使用属性split来返回分隔符,当它们被捕获时.这很整洁,但在某种意义上它颠倒了它的主要目的,即从字符串中提取其他组件,由模式分隔.因此,它可能使代码的目的有点复杂,并且您还必须非常精确地索引以检索您需要的内容.

而不是使用split提取由正则表达式给出的分隔符​​本身,为什么不通过正则表达式提取它?这也意味着清晰.例如,输入

@cluster t.10 has 4319 elements, 0 subclusters 
37652 ../../../../clust/output43888.txt 1.397428

解析可以像

if ($line =~ m/^\@cluster/) {
    ($key) = $line =~ /t\.(\d+)/;
}   
elsif ($line =~ m/^(\d+)/) { 
    ($value) = $line =~ m|.*/(\w+\.txt)|;
}    
$hash{$key} = $value if defined $key and defined $value;
Run Code Online (Sandbox Code Playgroud)

添加的位置t\.\.txt更精确地指定目标.如果目标字符串不确定具有那种精确的形式,则只需捕获\d+,在第二种情况下,所有非空格都在最后一个之后/,例如m|^\d+.*/(\S+)|.我们使用贪婪.*,它匹配所有可能的东西,直到它后面的东西(a /),因此一直到最后/.

然后,您还可以将其减少为每行的单个正则表达式

if ($line =~ m/^\@cluster\s+t\.(\d+)/) {
    $key = $1;
}
elsif ($line =~ m|^\d+.*/(\w+\.txt)|) {
    $value = $1;
}
Run Code Online (Sandbox Code Playgroud)

请注意,我已为哈希分配添加了一个条件.实际上,原始代码在undef第一次迭代时分配,因为$value此时尚未看到.这会在下一次迭代时被覆盖,如果我们之后只打印哈希,我们就不会看到它.对于格式错误的线路等,该条件还可以防止失败的匹配.当然,可以运行更好的检查.