我有一个日志文件,其中一些条目如下所示:
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>=
所以我希望解析这个仍然是可能的。答案 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
,如果日志变得非常大(性能明智),您将看到它的好处。