假设我有一个文件,其中的行数如下。
*some numbers* :00: *somenumbers*
*somenumbers* :21: *somenumbers*
对于每一个介于 ::
我需要计算它在文件中重复了多少次?
while (<>){
chomp($_);
my ($nebitno,$bitno,$opetnebitno) = split /:/, $_;
$count{$bitno}++;
}
foreach $bitno(sort keys %count){
print $bitno," ",$count{bitno}, "\n";
}
你生成的代码并不差--它一次只完成了一个文件的工作。将问题中所示的代码改编为处理多个文件,在每个文件之后重置计数。
#!/usr/bin/perl
use strict;
use warnings;
my %count = ();
while (<>) {
my ($nebitno, $bitno, $opetnebitno) = split /:/, $_;
$count{$bitno}++;
}
continue
{
if (eof) {
print "$ARGV:\n";
foreach $bitno (sort keys %count) {
print "$bitno $count{bitno}\n";
}
%count = ();
}
}
这里的关键是... continue
块,而 if (eof)
测试。 您可以使用 close $ARGV
在继续块中重置 $.
(行号),当文件发生变化时,它是一种常见的用法。 这种每个文件的摘要是另一种用法。 其他的变化都是表面上的。 你不需要咬住行号(虽然这样做并没有什么特别的坏处);我打印整个字符串,而不是使用逗号分隔的列表(它在这里很好用,而且很常见)。 我多用了几个空格。 我给代码块留了1TBS格式,虽然我自己不用这个格式(我用Allman)。
我的解决方案草案几乎使用了与上图相同的打印代码,但主要的 while
循环略有不同。
#!/usr/bin/env perl
use strict;
use warnings;
my %counts = ();
while (<>)
{
$counts{$1}++ if (m/.*:(\d+):/);
}
continue
{
if (eof)
{
print "$ARGV:\n";
foreach my $number (sort { $a <=> $b } keys %counts)
{
print ":$number: $counts{$number}\n"
}
%counts = ();
}
}
唯一的优点是如果某行没有冒号包围的数字,它就会忽略这行,而你的循环没有考虑这种可能性。 我不知道你的比较代码中的 sort
是有必要的--虽然它能确保比较的是数字。 如果数字的长度都是一样的,而且在必要的时候在左边加零垫,就没有问题。 如果它们的格式比较一般,"强制数字 "比较可能会有所区别。
记住:这是Perl,所以TMTOWDTI(There's More Than One Way To Do It)。 别人可能会提出一个更简单的解决方案。
以下代码可以达到预期的输出效果
:\d+:
一字排开%count
对于数字use strict;
use warnings;
use feature 'say';
my %count;
/:(\d+):/ && $count{$1}++ for <>;
say "$_ = $count{$_}" for sort keys %count;