【问题标题】:How to match over multiple lines in Perl when reading input from the pipe从管道读取输入时如何在 Perl 中匹配多行
【发布时间】:2015-10-28 09:52:48
【问题描述】:

我想从日志文件中提取数据。 该数据跨越多行。 起始行包含时间戳、线程 ID 和其他一些相关属性。 结束行包含线程 ID 和该线程工作多长时间忙碌的经过时间。 应将结果写入 CVS 文件进行统计分析。 每个结果行应如下所示:起始行的时间戳、线程 ID、其他相关属性和经过的时间。

截断的“重新排列”日志如下所示:

2015-08-01 12:23:21.123 | DEBUG | Thread-10 | Received message with id 1234 - com.example.product.module.Receiver#123
2015-08-01 12:23:21.123 | DEBUG | Thread-10 | some log message #1 - com.example.product.module.Helper1#123
2015-08-01 12:23:21.123 | DEBUG | Thread-10 | some log message #2 - com.example.product.module.Helper2#123
2015-08-01 12:23:21.123 | DEBUG | Thread-10 | some log message #3 - com.example.product.module.Helper3#123
2015-08-01 12:23:21.123 | DEBUG | Thread-10 | some log message #4 - com.example.product.module.Helper4#123
2015-08-01 12:23:21.224 | DEBUG | Thread-10 | Message processed in 101ms - com.example.product.module.Receiver#130

2015-08-01 12:24:21.123 | DEBUG | Thread-11 | Received message with id 2345 - com.example.product.module.Receiver#123
2015-08-01 12:24:21.123 | DEBUG | Thread-11 | some log message #1 - com.example.product.module.Helper1#123
2015-08-01 12:24:21.123 | DEBUG | Thread-11 | some log message #2 - com.example.product.module.Helper2#123
2015-08-01 12:24:21.123 | DEBUG | Thread-11 | some log message #3 - com.example.product.module.Helper3#123
2015-08-01 12:24:21.123 | DEBUG | Thread-11 | some log message #4 - com.example.product.module.Helper4#123
2015-08-01 12:24:21.225 | DEBUG | Thread-11 | Message processed in 102ms - com.example.product.module.Receiver#130

2015-08-01 12:25:21.123 | DEBUG | Thread-12 | Received message with id 3456 - com.example.product.module.Receiver#123
2015-08-01 12:25:21.123 | DEBUG | Thread-12 | some log message #1 - com.example.product.module.Helper1#123
2015-08-01 12:25:21.123 | DEBUG | Thread-12 | some log message #2 - com.example.product.module.Helper2#123
2015-08-01 12:25:21.123 | DEBUG | Thread-12 | some log message #3 - com.example.product.module.Helper3#123
2015-08-01 12:25:21.123 | DEBUG | Thread-12 | some log message #4 - com.example.product.module.Helper4#123
2015-08-01 12:25:21.226 | DEBUG | Thread-12 | Message processed in 103ms - com.example.product.module.Receiver#130

但实际上这些日志消息是混合的,因为应用程序同时运行多个线程。所以真正的日志是这样的:

2015-08-01 12:23:21.123 | DEBUG | Thread-10 | Received message with id 1234 - com.example.product.module.Receiver#123
2015-08-01 12:23:21.123 | DEBUG | Thread-10 | some log message #1 - com.example.product.module.Helper1#123
2015-08-01 12:23:21.123 | DEBUG | Thread-10 | some log message #2 - com.example.product.module.Helper2#123
2015-08-01 12:24:21.123 | DEBUG | Thread-11 | Received message with id 2345 - com.example.product.module.Receiver#123
2015-08-01 12:23:21.123 | DEBUG | Thread-10 | some log message #3 - com.example.product.module.Helper3#123
2015-08-01 12:24:21.123 | DEBUG | Thread-11 | some log message #1 - com.example.product.module.Helper1#123
2015-08-01 12:25:21.123 | DEBUG | Thread-12 | Received message with id 3456 - com.example.product.module.Receiver#123
2015-08-01 12:25:21.123 | DEBUG | Thread-12 | some log message #1 - com.example.product.module.Helper1#123
2015-08-01 12:24:21.123 | DEBUG | Thread-11 | some log message #2 - com.example.product.module.Helper2#123
2015-08-01 12:25:21.123 | DEBUG | Thread-12 | some log message #2 - com.example.product.module.Helper2#123
2015-08-01 12:23:21.123 | DEBUG | Thread-10 | some log message #4 - com.example.product.module.Helper4#123
2015-08-01 12:24:21.123 | DEBUG | Thread-11 | some log message #3 - com.example.product.module.Helper3#123
2015-08-01 12:23:21.224 | DEBUG | Thread-10 | Message processed in 101ms - com.example.product.module.Receiver#130
2015-08-01 12:24:21.224 | DEBUG | Thread-11 | some log message #4 - com.example.product.module.Helper4#123
2015-08-01 12:25:21.224 | DEBUG | Thread-12 | some log message #3 - com.example.product.module.Helper3#123
2015-08-01 12:25:21.224 | DEBUG | Thread-12 | some log message #4 - com.example.product.module.Helper4#123
2015-08-01 12:24:21.225 | DEBUG | Thread-11 | Message processed in 102ms - com.example.product.module.Receiver#130
2015-08-01 12:25:21.226 | DEBUG | Thread-12 | Message processed in 103ms - com.example.product.module.Receiver#130

我制作了一个能够在“重新排列”日志上执行匹配的正则表达式:

/(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}).*(Thread-\d+).*Received message with id (\d+) [\s\S]+?\2.*Message processed in (\d+)ms/g

打印捕获的组 (print "$1;$2;$3;$4\n";) 时所需的结果是:

2015-08-01 12:23:21.123;Thread-10;1234;101
2015-08-01 12:24:21.123;Thread-11;2345;102
2015-08-01 12:25:21.123;Thread-12;3456;103

当我使用 www.regexr.com 来尝试这些示例时,在重新排列的日志上运行会得到三个匹配项。

我现在的第一个问题是:当我想在 Perl 单行中使用正则表达式时,我无法在多行上执行匹配。我认为这与 -n 开关有关,它导致在 perl 代码周围添加一个循环,并且 perl 代码分别在每一行上执行。

cat files.log | perl -ne 'next LINE unless /(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}).*(Thread-\d+).*Received message with id (\d+) [\s\S]+?\2.*Message processed in (\d+)ms/gm; print "$1;$2;$3;$4\n";'

我面临的第二个问题是,在真正的日志文件中,日志文件排列得不是很好,我无法提取所有可能的匹配项。在给定的片段中,只能匹配一个结果,而不是所有三个。

我尝试将 Perl 命令中的记录分隔符设置为 undef $\=undef;,删除 next LINE unless...

谁能给我指出一个可能有帮助的方向?

日志文件可能会变得相当大(~200mb),因此将所有行组合成一个巨大的字符串似乎不是一个好方法,虽然我还没有尝试过。

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    散列通常用于分组。

    my %buf;
    while (<>) {
       chomp;
       my @fields = split / \| /;
       my $id = $fields[2];
       push @{ $buf{$id} }, \@fields;
       process(@{ delete($buf{$id}) })
          if $fields[3] =~ /^Message processed in /;
    }
    

    process 为每组行调用。 process 的每个参数都是一行,作为对字段数组的引用。

    【讨论】:

    • 我没有尝试过这个 Perl 脚本,但我希望得到一个非常不同的结果,比如所需的 CSV 格式...
    • 手头的问题是关于按线程对记录进行分组。你是说你也有输出 CSV 的问题吗?您应该从使用 Text::CSV_XS 开始。如果您对模块有疑问,请针对您的工作和问题发布适当的问题。
    • 好吧,我不是 Perl 黑客,我只是偶尔使用 Perl 来使用正则表达式从日志文件中提取数据。这非常方便,我希望使用 Perl 和正则表达式提取跨越多行的数据也不会太复杂。我通常通过将 perl 的 STDOUT 管道传输到文件来创建 CVS 文件。我从来没有为它使用过特殊的模块。我现在尝试了您的脚本,它在第 6 行“push”附近以语法错误终止
    • SO 不是代码编写服务。我们帮助人们解决编程问题。您遇到了分组记录的问题,我提供了解决方案。如果您对此有任何疑问,我将很乐意为您解答。我不知道你为什么还在谈论 CSV。
    • 我很清楚 SO 不是代码编写服务。但是我想学习一些关于正则表达式的新知识,以及当通过 STDIN 提供数据时 Perl 如何应用它们。我个人喜欢正则表达式,但不幸的是我不太习惯它们:)
    猜你喜欢
    • 2011-01-29
    • 1970-01-01
    • 2012-06-01
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多