Perl:计算重复项

3

我有以下的file.txt文件:

AAAA
BBBB
AAAA
CCCC
EEEE
AAAA

我已经编写了一个脚本来计算重复次数,将它们从高到低排序并打印出来。例如:

AAAA : 3
BBBB : 1
CCCC : 1
EEEE : 1

这段脚本是:

use v5.14;
use strict;

my %map;
chomp(my @chks = <FILE>);

foreach my $load (@chks) {
    $map{$load} += 1;
}

foreach my $key (sort keys %map) {
    say "$key : $map{$key} "
} 

但是输出结果却像这样:
 : 3
 : 1
 : 1
 : 1

为什么它无法看到$key的值?
1个回答

6
答案是你的输入文件来自Windows平台,它使用CR LF作为行结束符。当使用Perl在同一平台上读取文件时,通常会在输入时删除CR,但是如果您使用Linux系统读取文件,则CR将保留在原位。 Perl的chomp仅删除LF,使每个哈希键值的末尾仍保留CR。这将导致打印键时输出被覆盖。
解决方案要么使用:crlf PerlIO层打开文件,要么使用其他方法从输入中删除CR和LF的两者。
程序肯定还有更多内容,因为你没有在任何地方打开FILE。此外,你按哈希键的字典顺序而不是值的数值顺序排序输出。
以下是代码示例。:crlf层将CR LF行结束符转换为只有LF的输入,chomp现在将正确起作用,只剩下每行的文本。
use strict;
use warnings 'all';

my $filename = 'myfile.txt';

my @chks = do {
    open my $fh, '<:crlf', $filename or die qq{Unable to open "$filename" for input: $!};
    <$fh>;
};

chomp @chks;

my %map;

++$map{$_} for @chks;

for my $key ( sort { $map{$b} <=> $map{$a} } keys %map ) {
    print "$key : $map{$key}\n";
}

输出

AAAA : 3
CCCC : 1
BBBB : 1
EEEE : 1

如我所说,你可以使用替换chomp @chks的方式,而不是使用:crlf层。具体来说,你可以用s/\R\z// for @chks进行替换。其中,\R将匹配任何系统的行终止符:在这种情况下就是CR LF字符对。


1
@mkHun:这很令人鼓舞。谢谢你。 - Borodin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接