【问题标题】:Regex match last occurrence of a string from multiple lines正则表达式匹配多行中最后一次出现的字符串
【发布时间】:2026-02-08 01:15:01
【问题描述】:

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

[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...

以上是示例日志文件,其中以下字符串出现了 3 次,

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?见regex101.com/r/fnwPsB/2
  • 两者都很好用!太感谢了。 @anubhava 正是我所需要的。谢谢你们!
  • 仅供参考:要从整个匹配中获取子字符串,您需要使用capturing groups,因此\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}:\d{2} 模式应该用捕获括号括起来。

标签: regex regex-greedy


【解决方案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 Demo

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

这里(?!.* Moving message 123456789 from NEW to PENDING) 是负前瞻,确保我们匹配给定模式的最后一次出现。

【讨论】:

    【解决方案2】:

    你可以使用

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

    regex demo

    详情

    • (?s:.*\n)? - 一个内联修饰符组,它尽可能多地匹配任何 0+ 个字符,直到最后一个 LF 字符,然后是最后一次出现的后续模式。
    • \K - 匹配重置运算符从匹配内存缓冲区中删除到目前为止匹配的所有文本
    • \[(\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}:\d{2})\] Moving message 123456789 from NEW to PENDING - 使用第 1 组中捕获的日期时间获取的特定线条模式。

    或者,使用

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

    this regex demo

    详情

    • (?s) - DOTALL 修饰符使 . 匹配任何字符
    • (\[(\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}:\d{2})\] Moving message 123456789 from NEW to PENDING) - 匹配捕获到第 1 组和第 2 组中的日期时间的必要模式
    • (?!.*(?1)) - 如果在当前位置右侧的任何 0+ 个字符之后存在与第 1 组中定义的相同模式,则匹配失败。

    【讨论】:

    • @tuxian 刚刚注意到您需要单独捕获的日期,已编辑
    最近更新 更多