1

很抱歉问了很多次关于阅读线和其他东西的问题。我碰巧正在处理一个像这样的巨大(500,000 行)文件:

2013-05-27T19:01:23 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:29 [INFO] item_id:2, pause at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:3, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:3, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:3, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23

我需要做的是,将文件位置作为输入,制作一个脚本,其输出应类似于以下内容:

$output = [ {item_id => 1, counter => 2 }, { item_id...... 

也就是说,每个 item_id 都应该与它在数组 ref 中的开始数配对。请注意,我不能使用“while”多次读取文件,因为它太大了。另外,我不知道先验有多少项目。

我使用 Stackoverflow 成员的提示编写的方法如下:

sub count_start{
open LOGFILE, $file_location;
my $max;
my $i;
my $counter = 0;
my $found = 0;
my $data;

while (<LOGFILE>) {
  next unless /item_id:(\d+)/;
  $found = $1 if $found < $1;

  for ($i =1, $i<=$found, $i++){
   if ($file_location =~ /\bitem_id:$i, start\b/ig){
   $counter++;
   }
  $output = [ $i => $counter ];
  } 
}
close LOGFILE;
return $output;
}
1;

但是一切都出了问题:(。我收到了很多讨厌的警告,但没有任何与我被要求的类似的东西。有什么想法或建议吗?

原谅这个 perl 新手的糟糕代码。

4

2 回答 2

1

我会使用散列来进行计数,然后将其转换为散列数组。但是,看起来您正在使用 perl 代码来存储数据,这不是最好的主意。有更好的格式,例如JSON,甚至Text::CSV.

除此之外,该Data::Dumper模块可用于此目的。

use strict;
use warnings;
use Data::Dumper;

my %output;

while (<DATA>) {
    if (/ item_id:(\d+), start at /) {
        $output{$1}++;
    }
}

my @data = map { { item_id => $_, counter => $output{$_} } } keys %output;
print Dumper \@data;


__DATA__
2013-05-27T19:01:23 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:29 [INFO] item_id:2, pause at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:3, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:3, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:3, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23

输出:

$VAR1 = [
          {
            'counter' => 5,
            'item_id' => '1'
          },
          {
            'counter' => 3,
            'item_id' => '3'
          },
          {
            'counter' => 5,
            'item_id' => '5'
          }
        ];

请注意,由于哈希未排序,因此输出未排序。如果要对其进行排序,可以将该sort功能应用于键。

另请注意,此版本考虑到您说要计算“开始”,该输入不包括表示item_id:2, pause at.

于 2013-05-28T05:56:30.767 回答
1

您不能将类似哈希的关联放在列表中。为此,您需要一个哈希:

use strict;
use warnings;
my %output;
my $filename = shift @ARGV;
open my $file, "<", $filename or die("$!: $filename");
while (<$file>) {
    if (/item_id:(\d+)\s*,\s*start/) {
        $output{$1}++;
    }
}
close $file;
for my $item(keys %output) {
    print "$item -> $output{$item}\n";
}

输出

1 -> 5
3 -> 3
5 -> 4

你可以用这个替换while循环:

/item_id:(\d+)\s*,\s*start/ and $output{$1}++ while <$file>;

但它不是真正可读的。

于 2013-05-28T05:23:32.700 回答