我正在尝试读取多个具有相同格式的文件,并希望根据正则表达式进行一些统计。
即我想计算[]
中的类似项目 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;
提前致谢
答案 0 :(得分:3)
首先,总是 use strict
和use 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}
,这使循环完全冗余。