为日志文件创建一种“可组合”的解析器

时间:2009-10-24 14:01:00

标签: perl parsing

我已经启动了一个小宠物项目来解析Team Fortress 2的日志文件。日志文件在每一行都有一个事件,如下所示:

L 10/23/2009 - 21:03:43: "Mmm... Cycles!<67><STEAM_0:1:4779289><Red>" killed "monkey<77><STEAM_0:0:20001959><Blue>" with "sniperrifle" (customkill "headshot") (attacker_position "1848 813 94") (victim_position "1483 358 221")

请注意,日志文件的语法有一些共同部分。例如,名称由四部分组成:名称,ID,Steam ID以及当时玩家的团队。我没有重写这种正则表达式,而是希望稍微抽象出来。

例如:

my $name = qr/(.*)<(\d+)><(.*)><(Red|Blue)>/
my $kill = qr/"$name" killed "$name"/;

这很好用,但正则表达式现在返回依赖于$name格式的结果(打破了我想要实现的抽象)。上面的示例将匹配为:

my ($name_1, $id_1, $steam_1, $team_1, $name_2, $id_2, $steam_2, $team_2)

但我真的在寻找类似的东西:

my ($player1, $player2)

其中$ player1和$ player2将是之前数据的元组。我认为“杀死”事件不需要确切知道玩家,只要它有创建玩家的信息,这就是这些元组所提供的。

对不起,如果这有点絮絮叨叨,但希望你能提供一些建议!

3 个答案:

答案 0 :(得分:4)

我想我明白你在问什么。你需要做的是扭转你的逻辑。首先,你需要正则表达式将字符串分成两部分,然后你提取你的元组。然后你的正则表达式不需要知道名称,你只需要两个通用的播放器解析正则表达式。这是一个简短的例子:

#!/usr/bin/perl

use strict;
use Data::Dumper;

my $log = 'L 10/23/2009 - 21:03:43: "Mmm... Cycles!<67><STEAM_0:1:4779289><Red>" killed "monkey<77><STEAM_0:0:20001959><
Blue>" with "sniperrifle" (customkill "headshot") (attacker_position "1848 813 94") (victim_position "1483 358 221")';

my ($player1_string, $player2_string) = $log =~ m/(".*") killed (".*?")/;
my @player1 = $player1_string =~ m/(.*)<(\d+)><(.*)><(Red|Blue)>/;
my @player2 = $player2_string =~ m/(.*)<(\d+)><(.*)><(Red|Blue)>/;

print STDERR Dumper(\@player1, \@player2);

希望这是你想要的。

答案 1 :(得分:1)

另一种方法,但与dwp的答案相同:

my @players = 
    map { [ /(.*)<(\d+)><(.*)><(Red|Blue)>/ ] }
    $log_text =~ /"([^\"]+)" killed "([^\"]+)"/
;

您的日志数据包含几个平衡文本项(带引号和括号),因此您可能会考虑Text::Balanced部分此作业,或者可能是解析方法而不是使用正则表达式直接攻击。例如,如果玩家名称可以包含任意输入,后者可能会很脆弱。

答案 2 :(得分:1)

考虑编写Regexp::Log子类。