具有前瞻性的多行正则表达式

multiline regex with lookahead

我目前正在尝试使用正则表达式读取日志文件。我的日志以时间戳开头,后跟随机多行消息,其中可以包含多个换行符、returns 和所有类型的字符。

正则表达式应捕获以时间戳开头的所有内容,即实际日志消息,直到我们到达新的时间戳。目前,我通过在下一个时间戳之前使用积极的前瞻来做到这一点。

在网站上 regex101 代码或多或少有效。在我们的安全事件管理器中,相同的正则表达式不起作用。我需要保存每个事件,时间戳是第一个捕获组,日志消息是第二个捕获组。

(\w{3}\s{1}\w{3}\s{1}\d{2}\s{1}\d{2}\:\d{2}\:\d{2}\s{1}\d{4})((\r||.|\n)*)(?=(\w{3}\s{1}\w{3}\s{1}\d{2}\s{1}\d{2}\:\d{2}\:\d{2}\s{1}\d{4}))

示例日志:

Tue Sep 14 08:57:47 2021 Thread 1 advanced to log sequence 186 (LGWR switch) Current log# 2 seq# 186 mem# 0: D:\ORADB\DV1\REDO02A.LOG Current log# 2 seq# 186 mem# 1: H:\ORADB\DV1\REDO02B.LOG Tue Sep 14 09:07:40 2021 Thread 1 advanced to log sequence 187 (LGWR switch) Current log# 3 seq# 187 mem# 0: D:\ORADB\DV1\REDO03A.LOG Current log# 3 seq# 187 mem# 1: H:\ORADB\DV1\REDO03B.LOG Tue Sep 14 09:22:09 2021 Thread 1 advanced to log sequence 188 (LGWR switch) Current log# 4 seq# 188 mem# 0: D:\ORADB\DV1\REDO04A.LOG Current log# 4 seq# 188 mem# 1: H:\ORADB\DV1\REDO04B.LOG

regex101

顺便说一句,代码只有在我包含正则表达式的 \r||.|\n“或空”部分时才有效,我根本不明白。

您可以使用 [\s\S]* 来匹配任何字符,因为 \s 用于空格(包括换行符)而 \S 用于非空格。为了让它不跨越整个文本,换句话说它是非贪婪的,使用 ? 符号,例如[\s\S]*?试试这个模式:

(\w{3}\s\w{3}\s\d{2}\s\d{2}:\d{2}:\d{2}\s\d{4})([\s\S]*?)(?=\w{3}\s\w{3}\s\d{2}\s\d{2}:\d{2}:\d{2}\s\d{4}|\Z)

其中:

  • ( - 第一个捕获组开始
    • \w{3}\s\w{3}\s\d{2}\s - 匹配 Tue Sep 14
    • \d{2}:\d{2}:\d{2}\s\d{4} - 匹配 08:57:47 2021
  • ) - 第一个捕获组结束
  • ( - 第二个捕获组开始
    • [\s\S]*? - 匹配任何字符,包括换行符。匹配将以非贪婪的方式进行(因此匹配最少)。
  • ) - 第二个捕获组结束
  • (?= - 前瞻断言的开始
    • \w{3}\s\w{3}\s\d{2}\s\d{2}:\d{2}:\d{2}\s\d{4} - 下一部分必须是时间戳(这与整个正则表达式第一部分中时间戳的匹配模式相同)。
    • | - 或者
    • \Z - 或者下一部分必须是字符串的结尾
  • ) - 前瞻断言结束。请注意,由于在此之前的模式是非贪婪的,因此这将始终是最接近的时间戳,因此始终是下一个时间戳。