读取日志文件

时间:2011-04-18 15:09:24

标签: regex perl

我想读取日志文件并将其拆分为4个标量。

这是日志文件示例:

    [time1] [error1] [who is1] mess is here1
    [time2] [error2] mess is here2

并希望获得这些标量:

 ($time, $err, $who, $mess)=('time1', 'error1', 'who is1', 'mess is here1')
 ($time, $err, $who, $mess)=('time2', 'error2', '', 'mess is here2') 

如何在perl中执行此操作?

我的代码就像它,但它不起作用:

while (<MYFILE>) {
        chomp;
            ($time, $err, $who, $mess)=($_ =~/\[([.]*)\] \[([.]*)\] (\[([.]*)\]|[ ])([.]*)/);
            $logi.= "<tr><td>$time</td><td>$err</td><td>$who</td><td>$mess</td></tr>\n";

}

3 个答案:

答案 0 :(得分:6)

这是一种利用compiled regexes和/ x标志来更容易理解的方法,可以忽略空格。

my $block_re = qr{ \[ (.*?) \] }x;    # [some thing]
my $log_re = qr{^
    $block_re \s+ $block_re \s+ (?: $block_re \s+ )?  # two or three blocks
    (.*)                                              # the log message
$}x;

while($line = <$fh>) {
    my @fields = $line =~ $log_re;
    my $message = pop @fields;
    my($time, $err, $who) = @fields;

    print "time: $time, err: $err, who: $who, message: $message\n";
}

块正则表达式的关键之一是使用“非贪婪”匹配运算符.*?。通常.*将匹配最长的字符串,这意味着m{ \[ .* \] }x将匹配所有“[foo] [bar] [baz]”,而不仅仅是“[foo]”。通过添加?告诉它非贪婪,它将匹配最短的只是“[foo]”。

我做的另一个修改是将最后一个字段而不是第四个字段视为消息字段。我怀疑你的格式可以包含任意数量的“[foo]”块。

答案 1 :(得分:2)

my ($time, $err, $who, $mess)=($_ =~/\[(.*?)\]\s+\[(.*?)\]\s+(?:\[(.*?)\]|)\s*(.*)/);
$logi.= "<tr><td>$time</td><td>$err</td><td>".($who||"")."</td><td>$mess</td></tr>\n";

我们的想法是将第三个位置与[block] nothing 匹配。这是这样做的:

(?:\[(.*?)\]|)
如果该部分不匹配,则

$who保持未定义。打印输出中的$who||""是为了防止在那里使用带有连接的未定义值的警告。

答案 2 :(得分:1)

我必须不同意其他答案'使用非贪婪量词的建议(即.*?)。假设]不是您的时间/错误/字段中的有效字符,您正在寻找任意字符的最短可能序列,然后是{{ 1}}。您正在寻找最长的非]字符序列,这些字符正确写为]。这样做更有效率(正则表达式引擎在看到[^]]*时可以立即停止,而不是可能进行大量的回溯以找到替代匹配)并且更准确地将您的意图传达给未来的程序员阅读代码。

]

输出:

#!/usr/bin/env perl

use strict;
use warnings;

while (<DATA>) {
  chomp;
  my ($time, $err, $who, $mess) =
    ($_ =~/\[([^]]*)\] \[([^]]*)\] (?:\[([^]]*)\] )?(.*)/);
  $who ||= '(unspecified)';
  print "$time - $err - $who - $mess\n";
}

__DATA__
[time1] [error1] [who is1] mess is here1
[time2] [error2] mess is here2

顺便提一下,你的初始正则表达式中的核心问题无论如何都不是贪婪的匹配......你试图匹配time1 - error1 - who is1 - mess is here1 time2 - error2 - (unspecified) - mess is here2 ,它只匹配文字[.]*个字符的序列;它会在日志条目“[...] [..] [......] ..........”上运行良好,但对于包含的条目完全不匹配除.分隔符以外的字符,分隔字段的空格和字段内容的点。