Perl - 哈希

时间:2016-06-22 19:50:59

标签: arrays perl hash

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

例如,我的输入如下:

@cluster t.18
46421 ../../../output###.txt/
@cluster t.34
41554 ../../../output###.txt/

我从第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;
}

1 个答案:

答案 0 :(得分:6)

这是一个好主意,但在$key 中使用my创建的if是一个作用于该块的局部变量,掩盖全球$key。在if块内,符号$key与您提前声明的那个没有任何关系。请参阅my in perlsub

$key完成if后,本地if超出范围,并且在$key块之外不存在。全局if$value之后再次可用,在循环中的其他位置可见,但未定义,因为它从未被分配到。 elsif 中的my也是如此。

只需将$key = ...声明放入循环中,从而分配给那些全局变量(如预期的那样?)。因此,$value = ...input.txt会正确分配哈希值。

注意 - 这是关于如何正确地获得该哈希分配。我不知道您的实际数据是如何看的以及该行是否被正确解析。这是一个玩具$value = $output[3];

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

我选择第4个字段而不是第6个字段print "$_ => $hash{$_}\n" for keys %hash; ,然后添加

split
循环后

。这打印

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

我不确定这是否是你想要的,但是哈希建立得很好。

关于解析

中工具选择的评论

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

不是使用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; 来提取由正则表达式给出的分隔符​​本身,为什么不用正则表达式提取它?这也意味着清晰。例如,输入

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

解析可以作为

t\.

添加\.txt\d+以更精确地指定目标。如果目标字符串不能确定具有该精确形式,则只需捕获/,在第二种情况下,在m|^\d+.*/(\S+)|之后的所有非空格,例如.*。我们使用/的贪婪,它将所有与之后的事物(一个/)相匹配,从而一直到最后{{1} }}

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

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

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