perl哈希数组从文件中读取

时间:2012-09-16 19:17:38

标签: regex perl foreach hashtable

我正在尝试读取多个具有相同格式的文件,并希望根据正则表达式进行一些统计。

即我想计算[]

中的类似项目
 NC_013618 NC_013633 ([T(nad6 trnE ,cob trnT ,)])
C_013481 NC_013479 ([T(trnP ,rrnS trnF trnV rrnL nad1 trnI ,)])
NC_013485 NC_003159 ([T(trnC ,trnY ,)])
NC_013554 NC_013254 ([T(trnR ,trnN ,)])
NC_013607 NC_013618 ([T(nad6 trnE ,cob trnT ,)])

问题是我没有得到正确的值,下面是我的代码:

 use strict;
 use warnings;

my %data;
@FILES = glob("../mitos-crex/*.out");
foreach my $file (@FILES) {
    local $/ = undef;
    open my $fh, '<', $file;
    $data{$file} = <$fh>;
}

my @t;
my $c = 0;
foreach my $line (keys %data) {
    foreach my $l ($data{$line}) {
         print $l."\n";
        ($t[$c]) = $l =~ m/(\[.*\])/;

        $c++;
    }
}

#the problem is here the counter is not giving the right value

print $c;
my %counts;
$counts{$_}++ for @t;

提前致谢

2 个答案:

答案 0 :(得分:3)

首先,总是 use strictuse warnings。这一措施对于所有编程都至关重要,因为它可以快速揭示您可能忽略的简单问题或浪费时间进行调试。如果您要求其他人帮助您的计划

,这一点尤为正确且简单礼貌

你似乎已经把 slurping 整个文件变成了一个单独的字符串,变成了一个行数组。你编写它的方式,每个元素$data{file}是一个包含所有文件数据的标量值,然后你尝试用foreach $l ($data{$line}) { ... }迭代它只执行一次,所以只找到第一个文件中的[...]字符串

通常我会说你不应该以这种方式读取所有文件数据,因为问题可能有更好的流式解决方案,但我不知道你还想用什么来捕获数据因为,我的解决方案遵循您自己的设计

我认为你需要将数据压入虚拟数组而不是标量,然后在循环中迭代它。您必须保留$/定义,以便按行读取文件,并使用[ <$fh> ]构建匿名数组。然后,您可以使用foreach my $line (@{ $data{$file} }) { ... }

遍历这些行
use strict;
use warnings;

my %data;

my @files = glob("../mitos-crex/*.out");

foreach my $file (@files) {
    open my $fh, '<', $file or die $!;
    $data{$file} = [ <$fh> ];
}

my $c = 0;
my @t;
foreach my $file (keys %data) {
    foreach my $line (@{ $data{$file} }) {
        ($t[$c]) = $line =~ /(\[.*\])/;
        $c++;
    }
}

print $c;
my %counts;
$counts{$_}++ for @t;

答案 1 :(得分:0)

计数器给出正确的值。你的问题是你正在啜饮文件(一次读取所有内容),但只存储找到的第一个值:

($t[$c]) = $data{$line} =~ m/(\[.*\])/;  # only finds first value in file

正确循环遍历每个文件,并为每一行使用上述正则表达式,或执行以下操作:

push @t, ($data{$line} =~ m/(\[.*\])/g);

你应该总是使用

use strict;
use warnings;

并解决导致的错误/警告。不这样做是一个坏主意,只是隐藏代码中的问题 - 而不是解决它们。

另外,你应该知道这句话:

foreach $l ($data{$line}) {

只迭代一次,因为这里的每个“行”都是整个文件,而$data{$line}除了标量值之外。此外,您使用$l作为别名进行迭代,但仍然在循环中使用$data{$line},这使循环完全冗余。