使用perl解析日志文件

时间:2011-05-12 13:24:42

标签: perl pattern-matching

我有一个日志文件,其中一些条目如下所示:

YY/MM/DD HH:MM:SS:MMM <Some constant text> v1=XXX v2=YYY v3=ZZZ v4=AAA AND BBB v5=CCC

我想把它变成CSV格式:

Date,Time,v1,v2,v3,v4,v5
YY/MM/DD,HH:MM:SS:MMM,XXX,YYY,ZZZ,AAA AND BBB,CCC

我想在Perl中这样做 - 就个人而言,我可能在其他语言中做得更快,但我真的想扩大我的视野。

到目前为止,我可以阅读文件,只选择符合我标准的行,但我似乎无法完成下一阶段的工作。我需要拼接输入线,但到目前为止我还是无法解决如何做到这一点。我看过s//m//,但他们并没有真正给我我想要的东西。如果有人可以告诉我如何做到这一点或给我指点,我会非常感激。

要点:

  • 该行第二部分的值总是以相同的顺序排列,因此映射/重新组织不一定是个问题。
  • 有些字段有自由文本没有引用:(但是因为标签都是v<number>=所以我希望解析这个仍然是可能的。

3 个答案:

答案 0 :(得分:6)

由于没有一个分隔符,您需要尝试以下几种方式:

首先,在' '上拆分,然后取前三个值:

my @array = split / /, $line;
my ($date, $time, $constant) = splice @array, 0, 3;

再次将其余字段加入,并在v\d+=上重新拆分以获取值:

my $rest = join ' ', @array;

# $rest should now be "v1=XXX v2=YYY ..."
my @values = split /\s*v\d+=/, $rest;
shift @values; # since the first element in @values will be empty

print join ',', $date, $time, @values;

修改:这是另一种可能更容易理解的方法,效率稍高。这利用了在日期/时间和值列表之间出现常量文本的事实。

# assume that CONSTANT is your constant text
my ($datetime, $valuelist) = split /\s*CONSTANT\s*/, $line;
my ($date, $time) = split / /, $datetime;
my @values = split /\s*v\d+=/, $valuelist;
shift @values;

print join ',', $date, $time, @values, "\n";

答案 1 :(得分:4)

您尝试使用正则表达式,它是如何失败的? m//的正则表达式适用于我:

#!/usr/bin/env perl

use strict;
use warnings;

print "Date,Time,v1,v2,v3,v4,v5\n";

while (my $line = <DATA>) {
    my @matched = $line =~ m{^([^ ]+) ([^ ]+).*v1=(.*) v2=(.*) v3=(.*) v4=(.*) v5=(.*)};
    print join(',', @matched), "\n";
}

__DATA__
YY/MM/DD HH:MM:SS:MMM <Some constant text> v1=XXX v2=YYY v3=ZZZ v4=AAA AND BBB v5=CCC

两个警告:

1)v1不能包含子串“v2 =”,v2不能包含“v3 =”等,但是,如果这种松散的格式,那么对于试图解析它的人来说,这可能会引起问题

2)此代码假定始终存在v1到v5。如果少于五个v * n *字段,则该行将无法匹配。如果还有更多,则所有其他字段将附加到v5(包括其v * n *标记)。

答案 2 :(得分:1)

如果日志是固定宽度的,最好使用unpack,如果日志变得非常大(性能明智),您将看到它的好处。