在 Perl 中匹配多行格式不正确的文本
Matching multiple lines of poorly formatted text in Perl
我有来自外部程序的数据格式,如下所示,需要获取每行的前 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
在这个问题的帮助下,我能够获得多行正则表达式:
感谢@GsusRecovery!
因为我是逐行阅读输出,所以我不认为我可以通过阅读单行来利用多行正则表达式。如果格式在一行中是否可以只读取一行或者如果它在 3 行中展开为 2 或 3 行是否可以读取 2 行?
还是根据双行或三行格式阅读每一行和回溯更好。
求推荐。
最好使用单一方法而不是在每行上切换,因为没有迹象表明 single/multi 行可以预先发生。因为您有 (int) 和 (date) 的固定格式,所以只需使用多行正则表达式模式,它会匹配如下内容:(伪正则表达式代码)
\s+ (.*) \s+ (.*) (\d+) (\d+\/\d+\/\d+ \d+\:\d+ [AP]M)$
space text space name int date
不要忘记使用 /m 进行多行匹配。因为 single/multi 行模式除了 \n 和额外的间距外几乎完全相同,所以在所有情况下都可以使用相同的模式。
更新:我已经更改脚本以接受标准输入并将其作为数组放入@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:如果你处理一个流或者如果你的文件大于系统的易失性内存(所以你想把它作为一个流来处理),就需要这种方法) 但是,也就是说,它在任何情况下都有效。
我有来自外部程序的数据格式,如下所示,需要获取每行的前 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
在这个问题的帮助下,我能够获得多行正则表达式:
感谢@GsusRecovery!
因为我是逐行阅读输出,所以我不认为我可以通过阅读单行来利用多行正则表达式。如果格式在一行中是否可以只读取一行或者如果它在 3 行中展开为 2 或 3 行是否可以读取 2 行?
还是根据双行或三行格式阅读每一行和回溯更好。
求推荐。
最好使用单一方法而不是在每行上切换,因为没有迹象表明 single/multi 行可以预先发生。因为您有 (int) 和 (date) 的固定格式,所以只需使用多行正则表达式模式,它会匹配如下内容:(伪正则表达式代码)
\s+ (.*) \s+ (.*) (\d+) (\d+\/\d+\/\d+ \d+\:\d+ [AP]M)$
space text space name int date
不要忘记使用 /m 进行多行匹配。因为 single/multi 行模式除了 \n 和额外的间距外几乎完全相同,所以在所有情况下都可以使用相同的模式。
更新:我已经更改脚本以接受标准输入并将其作为数组放入@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:如果你处理一个流或者如果你的文件大于系统的易失性内存(所以你想把它作为一个流来处理),就需要这种方法) 但是,也就是说,它在任何情况下都有效。