我不确定如何正确初始化我的哈希 - 我正在尝试为输入文件中的耦合行中的值创建键/值对.
例如,我的输入如下所示:
@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)
这是一个好主意,但是你在块中$key创建my的是一个局限于该if 块的局部变量,掩盖了全局$key.在if块内,符号$key与您提前声明的符号无关.见my in perlsub.
这个本地$key一旦if完成就超出了范围,并且在if块之外不存在.全局在循环中的其他位置可见$key后再次可用if,但由于从未分配过,因此未定义.这同样适用于$value在elsif 块.
只需将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此时尚未看到.这会在下一次迭代时被覆盖,如果我们之后只打印哈希,我们就不会看到它.对于格式错误的线路等,该条件还可以防止失败的匹配.当然,可以运行更好的检查.