1

我真的需要 Perl 黑客的帮助。这看起来很容易,但我已经考虑了一个小时并没有提供任何解决方案。

假设我们有一个平面文件或日志文件,如下所示:

    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
    (...)

我必须创建一个方法来找到最大的 item_id 编号,在本例中为 5,并将其定位在变量 $found 中。请注意,我们不知道先验是最大的数字,所以我不能使用 grep 因为我需要将“最大的数字(在这种情况下为 5)”作为输入。我们唯一的输入是文件的位置。你有什么建议?

4

4 回答 4

4

这个解决方案非常简单。它期望输入文件的名称作为命令行上的参数。

use strict;
use warnings;

my $found = 0;

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

print "Found: $found";

输出

Found: 5

更新

如果你想要的只是这个值,那么就有这个命令行版本

perl -ne "/item_id:(\d+)/ && $f<$1 and $f=$1; END{print $f}" data.txt
于 2013-05-28T01:28:59.857 回答
3

只需读取日志文件的每一行并使用正则表达式获取游戏 id,用第一个初始化游戏 id,并在获得更大的 id 时替换它。

use strict;
use warnings;

my $location = "file.txt";
open LOGFILE, $location;

my $first_line = 1;
my $max_id;

while (<LOGFILE>) {
    if (/item_id:(\d)+/) {
        if ($first_line) {
            $first_line = 0;
            $max_id = $1;
        } else {
            $max_id = $1 if ($1 > $max_id);
        }
    }
}

my $found = $max_id;
print "$found\n";

close LOGFILE;
于 2013-05-28T01:20:46.197 回答
3

List::Util有一个 max() 函数,它将选择最大的数字。

use List::Util qw(max);

my @ids;
while(my $line = <$fh>) {
    my($id) = $line =~ /item_id:(\d+)/;
    push @ids, $id;
}

print max(@ids);

对于教育, max 是一个非常简单的实现功能。

sub max {
    my $max;
    for my $num (@_) {
        $max = $num if $num > $max;
    }

    return $max;
}

如果您有大量的行,您可以在循环中进行最大计算以避免存储列表。

my $max;
while(my $line = <$fh>) {
    my($id) = $line =~ /item_id:(\d+)/;
    $max = $id if $id > $max;
}
于 2013-05-28T01:21:25.573 回答
2

作为 Perl 单行:

perl -lne '{$s{$1}++ if /item_id:(\d+)/} END{print ((sort keys %s)[-1])}' input

或者,

perl -nle '{$m = $1 if /item_id:(\d+)/ and $1 > $m} END{print $m}' input

因为您提到了 grep,所以这是一种使用命令行工具执行此操作的方法:

cut -d' ' -f3 input | sed 's/[^:]*:\([0-9]*\),/\1/' | sort -nr | head -1

或者,

sed 's/.*item_id:\([0-9]*\),.*/\1/' input | sort -nr | head -1
于 2013-05-28T01:25:31.997 回答