从文件中读取perl散列数组



我正在尝试读取多个具有相同格式的文件,并希望基于regex进行一些统计。

即,我想统计[]中的类似项目

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;

提前感谢

首先,始终use strictuse warnings。这一措施对所有编程都至关重要,因为它会很快揭示一些简单的问题,否则您可能会忽略这些问题或在调试上浪费时间。如果你在你的程序中寻求他人的帮助,这是一个特别真实和简单的礼貌

您似乎已经混淆了将整个文件模糊为单个字符串和行数组。按照您的编写方式,每个元素$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;

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

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

正确地循环每个文件,并对每一行使用上面的regex,或者执行以下操作:

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

您应该始终使用

use strict;
use warnings;

并解决由此产生的错误/警告。不这样做是个坏主意,只会将问题隐藏在代码中,而不是解决它们。

此外,您应该注意以下声明:

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

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

最新更新