【问题标题】:Perl multiline regex for first 3 individual items前 3 个单独项目的 Perl 多行正则表达式
【发布时间】:2016-01-08 18:50:37
【问题描述】:

我正在尝试在 Perl 中读取正则表达式格式。有时我也会看到 3 行的格式,而不是单行。

对于下面的单行格式,我可以正则表达式为

/^\s*(.*)\s+([a-zA-Z0-9._]+)\s+(\d+)\s+(.*)/

获取前 3 个单独的项目

Hi There       FirstName.LastName    10  3/23/2011 2:46 PM

下面是我看到的多行格式。我正在尝试使用类似的东西

/^\s*(.*)\n*\n*|\s+([a-zA-Z0-9._]+)\s+(\d+)\s+(.*)$/m

获取单个项目,但似乎不起作用。

Hi There    

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

Testing - 12323232323 Hello There

有什么建议吗?多行正则表达式可以吗?

注意:在同一个输出中,我可以看到单行或多行或两者,因此输出可以如下所示

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

你好 Line2

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

Testing - 12323232323 Hello There

你好 Line3 Line3FirstName.LastName 8 3/21/2011 下午 2:46

【问题讨论】:

  • 预期输出是什么? FirstName-LastName 不会匹配 [a-zA-Z0-9._]+。什么是允许的“一行中的项目”?
  • 我认为您只需要添加- 部分[a-zA-Z0-9._] 就像[a-zA-Z0-9._-] ;)。
  • .* 对于第一项可能过于宽泛。也许你应该把它减少到\S+

标签: regex perl multiline


【解决方案1】:

您肯定可以在多行上应用正则表达式。

我在单词之间使用了否定词\W+ 来匹配单词之间的空格和换行符(实际上\W 等于[^a-zA-Z0-9_])。 聊天被视为重复 \w+\W+ 块。

如果您提供更具体的输入/输出案例,我可以改进示例代码:

#!/usr/bin/env perl

my $input = <<'__END__';
Hi There    

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

Testing - 12323232323 Hello There
__END__

my ($chat,$username,$chars,$timestamp) = $input =~ m/(?im)^\s*((?:\w+\W+)+)(\w+[-,\.]\w+)\W+(\d+)\W+([0-1]?\d\/[0-3]?\d\/[1-2]\d{3}\s+[0-2]?\d:[0-5]?\d\s?[ap]m)/;

$chat =~ s/\s+$//;  #remove trailing spaces

print "chat -> ${chat}\n";
print "username -> ${username}\n";
print "chars -> ${chars}\n";
print "timestamp -> ${timestamp}\n";

传奇

  • m/^.../ 从行首开始匹配正则表达式(不是替代类型)
  • (?im):不区分大小写的搜索和多行(^/$ 也匹配行的开始/结束)
  • \s* 匹配零个或多个空白字符(匹配空格、制表符、换行符或换页符)
  • ((?:\w+\W+)+)(匹配组 $chat)匹配一个或多个由单个单词组成的模式 \w+(字母、数字、'_')后跟非单词 \W+(所有非 \w 包括换行符 @ 987654335@)。这稍后会被过滤以删除尾随空格
  • (\w+[-,\.]\w+): (match group $username) 这是我们的弱点。如果用户名不是由两个由破折号 '-' 或逗号 ',' (UPDATE) 或点 '.' 分隔的正则表达式单词组成,则整个正则表达式无法正常工作(我已提取您的问题中的两种可能性都没有直接指定)。
  • (\d+): (match group $chars) 一个由一位或多位数字组成的数字
  • ([0-1]?\d\/[0-3]?\d\/[1-2]\d{3}\s+[0-2]?\d:[0-5]?\d\s[ap]m): (match group $timestamp) 这比其他人分开的要长:
    • [0-1]?\d\/[0-3]?\d\/[1-2]\d{3} 匹配由月份(可选前导零)、日(可选前导零)和 1000 到 2999 之间的年份组成的日期(宽松的约束:)
    • [0-2]?\d:[0-5]?\d\s?[ap]m 匹配时间:小时:分钟,可选空格和 'pm,PM,am,AM,Am,Pm...' 感谢上面不区分大小写的修饰符

你可以在线测试here

【讨论】:

  • 非常感谢您的意见。在我的场景中,除了多行之外,还可能有单行,如下所示:您好 FirstName.LastName 10 3/23/2011 2:46 PM 我正在​​尝试获取一个 RegEx 来处理行输出是否为 Single 和 MultiLine .如果您有任何想法,请提出建议。
  • @sureng:正则表达式已经适用于多行和单行输入。正如我在上面写的那样,弱点是$username 部分。在您提供的单行输入中,名字与姓氏之间用点分隔。我已经考虑过(使用您之前的示例逗号',' 和破折号'-'。我已经更新了答案以考虑点'.'
  • @sureng:现在online example 将正则表达式应用于单行和多行输入。
  • @GsussRecovery 非常感谢。你是对的。我没有考虑-。它适用于两种情况!....
  • 有趣的是我正在从另一个程序获得上述输出。由于我正在逐行阅读多个 RegEx 不起作用。有没有办法根据 RegEx 格式读取单行或多行。我给出的 3 种格式可以在同一个输出中。
【解决方案2】:

你的正则表达式说:

^\s*(.*)\n*\n*  # line starts with optional space followed by anything 
|      # or
\s+([a-zA-Z0-9._]+)\s+(\d+)\s+(.*)$ # spaces followed by any words followed by spaces, digits, spaces,  anything at the end of the line

考虑一下:

/^From|To$/

交替坚持尽可能接近序列。 上面真的是说要找到以'Fro'开头的行,然后是'm'或'T',然后是'o',然后是行尾

比较一下:

    /^(From|To)$/

上面会找到只有“From”或“To”的行

【讨论】:

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