【问题标题】:Matching multiple lines of poorly formatted text in Perl在 Perl 中匹配多行格式错误的文本
【发布时间】:2016-01-10 15:34:04
【问题描述】:

我有来自外部程序的如下数据格式,需要获取每行的前 4 个字段(文本、用户名、数字和时间戳)。请注意 Hello line1 是一个字段,第二个是用户名。输出的格式可以是像下面的 line1 这样的单行,也可以是像 line2 这样的三行,或者像下面的 line4 这样的两行。而且格式可以像下面这样混合(不是单行总是或双等)

Hello Line1 FirstName.LastName 10 3/23/2011 2:46 PM

Hello Line2

                         Line2FirstName-LastName       8       7/17/2015 1:15 PM 

Line2Testing - 12323232323 Hello There

Hello Line3 Line3FirstName.LastName 8 3/21/2011 2:46 PM

Hello Line4

                         Line4FirstName-LastName       8       9/17/2015 1:20 PM

Screen shot of above in a editor

借助这个问题,我能够获得 Multline RegEx:Perl multiline regex for first 3 individual items

感谢@GsusRecovery!

由于我正在逐行读取输出,我认为我不能通过读取单行来利用多行 RegEx。如果格式为一行,是否可以只读取单行,或者如果格式为 2 行,则可以读取 2 行,如果格式为 3 行,是否可以读取 3 行?

还是根据双行或三行格式读取每一行并回溯是否更好。

请提出建议。

【问题讨论】:

  • 请确保格式可以理解。我不知道哪条线在哪里。使用 4 空格缩进。
  • 考虑不逐行读取文件,使用需要匹配多行字符串中的组的正则表达式可能会获得更好的结果...另外,我 无法理解您的问题.
  • @amadan 抱歉,我添加了屏幕截图。发帖时我无法正确输入格式。
  • @PedroLobito 如何一次读取上述输出并应用多行正则表达式??
  • 以我们可以理解的方式编辑您的问题,您可能会得到适当的帮助。

标签: regex perl multiline


【解决方案1】:

更新:我已将脚本更改为接受标准输入并将其作为数组放入@output_lines(以模拟@sureng 的输入情况)

我已将正则表达式包装在一个行累加器中,该行累加器将小时识别为结束模式。通过这种方式,您可以逐行解析输出并应用正则表达式。

#!/usr/bin/perl

use strict;
use warnings;

my ($accumulator,$chat,$username,$chars,$timestamp);

my @output_lines = <STDIN>;

foreach (@output_lines)
{
    $accumulator .= $_;

   ($chat,$username,$chars,$timestamp) = $accumulator =~ m/(?im)^\s*(.+)\s+(\w+[-,\.]\w+)\s+(\d+)\s+([0-1]?\d\/[0-3]?\d\/[1-2]\d{3}\s+[0-2]?\d:[0-5]?\d\s?[ap]m)\s*$/;
    $chat =~ s/\s+$// if $chat;  #remove trailing spaces

    if ( $accumulator =~ /(?i)([0-2]?\d:[0-5]?\d\s?[ap]m)/ ) {
        print "SECTION matched\n";
        print "-"x80,"\n";
        print "$accumulator";
        print "-"x80,"\n";
        print "chat -> ${chat}\n";
        print "username -> ${username}\n";
        print "chars -> ${chars}\n";
        print "timestamp -> ${timestamp}\n\n";
        $accumulator = '';  # reset the line accumulator
    }
}

在线尝试解决方案(您的示例作为标准输入提供)here。

在你的 shell 中,给定上面的脚本和这个输入文件:

# MultiLineInput.txt
Hello Line1 FirstName.LastName 10 3/23/2011 2:46 PM

Hello Line2

                     Line2FirstName-LastName       8       7/17/2015 1:15 PM 
Line2Testing - 12323232323 Hello There

Hello Line3 Line3FirstName.LastName 8 3/21/2011 2:46 PM

Hello Line4

                     Line4FirstName-LastName       8       9/17/2015 1:20 PM

您可以简单地调用:

cat MultiLineInput.txt | StreamRegex.pl

如果它按预期工作,您可以用您的源代码替换 cat 命令。

NB:如果您处理流或文件大于系统的易失性内存(因此您希望将其作为流处理),则需要这种方法,但是,也就是说,它在任何情况下都有效。

【讨论】:

  • 感谢 GsusRecovery。我稍后会尝试一下。基本上在某一时刻我在@output_lines 中获得了整个输出,然后我需要根据你的while循环进行解析。不确定 在 while 循环中。将不得不研究更多..
  • while(&lt;&gt;) 在使用菱形运算符时,在这种情况下从标准输入读取行。我已经修改为使用while(&lt;STDIN&gt;) 更清晰
  • @sureng:我已经更新了答案以匹配您的输入(来自数组 @output_lines 的输入数据)
  • 非常感谢。你太有帮助了......再次感谢你的精彩技巧。
【解决方案2】:

最好使用单一方法,而不是打开每条线路,因为没有任何迹象表明何时可以事先发生单行/多行。因为您有 (int) 和 (date) 的固定格式,所以只需使用多行正则表达式模式,它会匹配如下内容:(伪正则表达式代码)

 \s+    (.*)   \s+  (.*)  (\d+) (\d+\/\d+\/\d+ \d+\:\d+ [AP]M)$
 space text  space  name  int   date

不要忘记使用 /m 进行多行匹配。因为除了 \n 和额外的间距之外,单行/多行模式几乎相同,因此可以在所有情况下使用相同的模式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多