从多行中匹配字符串的最后一个出现位置的正则表达式匹配

3

我正在尝试从日志文件中匹配字符串的最后一次出现。

[03/03/2019 09:16:36] Moving message 123456789 from NEW to PENDING
[03/03/2019 09:16:36] Retrieving file(s) of type DATAWAREHOUSE for 123456
[03/03/2019 09:16:36] collecting warehouse version 7.3.1 files for 123456...
[03/03/2019 09:16:37] Moving message 123456789 from NEW to PENDING
[03/03/2019 09:16:37] Retrieving file(s) of type DATAWAREHOUSE for 123456
[03/03/2019 09:16:37] collecting warehouse version 7.3.1 files for 123456...
[03/03/2019 09:16:38] Moving message 123456789 from NEW to PENDING
[03/03/2019 09:16:39] Retrieving file(s) of type DATAWAREHOUSE for 123456
[03/03/2019 09:16:40] collecting warehouse version 7.3.1 files for 123456...

以下是示例日志文件,其中有三个以下字符串的出现:
Moving message 123456789 from NEW to PENDING

我需要匹配最后一次出现的时间戳"[03/03/2019 09:16:38]"。当所有这些内容都在同一行时,使用贪婪匹配 (.*) 很好用。但是当它们存在于多行时就不起作用了。我没有尝试过多行(m),因为我不确定如何使用它。请有人帮我构建正则表达式查询以检索最后一次发生的时间戳吗? 示例:https://regex101.com/r/fnwPsB/1

也许你会想用这个正则表达式 (?s:.*\n)?\K\[\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}:\d{2}\] Moving message 123456789 from NEW to PENDING 去匹配文本?请参考 https://regex101.com/r/fnwPsB/2 - Wiktor Stribiżew
1
请查看此链接:https://regex101.com/r/fnwPsB/3 - anubhava
1
两个都很棒!非常感谢。 @anubhava的正是我所需要的。谢谢你们俩! - tuxian
请注意:如果要从整个匹配中获取子字符串,则需要使用捕获组,因此\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}:\d{2}模式应该用括号括起来进行捕获。 - Wiktor Stribiżew
2个回答

1

您可以使用

(?s:.*\n)?\K\[(\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}:\d{2})\] Moving message 123456789 from NEW to PENDING

请查看正则表达式演示

详情

  • (?s:.*\n)? - 内联修改器组,尽可能多地匹配0个或多个字符,直到最后一个LF字符,该字符后面跟随后续模式的最后一次出现。
  • \K - 匹配重置运算符,从匹配内存缓冲区中删除迄今为止匹配的所有文本
  • \[(\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}:\d{2})\] 将消息123456789从NEW移动到PENDING - 获取日期时间的特定行模式,在组1中捕获。

或者,使用

(?s)(\[\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}:\d{2}\] Moving message 123456789 from NEW to PENDING)(?!.*(?1))

请查看这个正则表达式演示

细节

  • (?s) - DOTALL修饰符使.匹配任何字符
  • (\[(\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}:\d{2})\] 将消息123456789从NEW移动到PENDING) - 匹配所需模式并捕获到第1组和第2组中的日期时间
  • (?!.*(?1)) - 负向先行断言,如果当前位置右侧的0个或多个字符中存在与第1组定义的相同模式,则匹配失败。

@tuxian 刚刚注意到你需要单独捕获日期,已编辑。 - Wiktor Stribiżew

1

这里有一个解决方案,不依赖于PCRE特性,使用负向先行断言:

(?s)\[(\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}:\d{2})\] Moving message 123456789 from NEW to PENDING(?!.* Moving message 123456789 from NEW to PENDING)

RegEx演示

日期时间在第一个捕获组中可用。

这里的(?!.*将消息123456789从NEW移动到PENDING)是负向先行断言,它确保我们匹配给定模式的最后一次出现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接