具有前瞻性的多行正则表达式
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
顺便说一句,代码只有在我包含正则表达式的 \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
- 或者下一部分必须是字符串的结尾
)
- 前瞻断言结束。请注意,由于在此之前的模式是非贪婪的,因此这将始终是最接近的时间戳,因此始终是下一个时间戳。
我目前正在尝试使用正则表达式读取日志文件。我的日志以时间戳开头,后跟随机多行消息,其中可以包含多个换行符、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
顺便说一句,代码只有在我包含正则表达式的 \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
- 或者下一部分必须是字符串的结尾
)
- 前瞻断言结束。请注意,由于在此之前的模式是非贪婪的,因此这将始终是最接近的时间戳,因此始终是下一个时间戳。