正则表达式 onigurama 负后视不起作用

regex onigurama Negative lookbehind not working

我正在尝试使用 Onigurama 正则表达式库(在 Logstash 中)使用负向后视来捕获日志文件中的一行,但它似乎仍然匹配它不应该匹配的行。我试图只匹配顶级异常,而不匹配以 Caused By:

开头的异常

有人帮我写的

在 Rubular 上测试 http://rubular.com/r/N3AzySNHiS

测试正则表达式

^(?<!Caused by: ).*?Exception

(?<!^Caused by: ).*?Exception

留言:

2016-11-15 05:19:28,801 ERROR [App-Initialisation-Thread] appengine.java:520 Failed to initialize external authenticator myapp Support Access || appuser@vm23-13:/mnt/data/install/assembly app-1.4.12@cad85b224cce11eb5defa126030f21fa867b0dad
java.lang.IllegalArgumentException: Could not check if provided root is a directory
    at com.myapp.jsp.KewServeInitContextListener.run(QServerInitContextListener.java:104)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.nio.file.NoSuchFileException: fh-ldap-config/
    at com.upplication.s3fs.util.S3Utils.getS3ObjectSummary(S3Utils.java:55)
    at com.upplication.s3fs.util.S3Utils.getS3FileAttributes(S3Utils.java:64)

Logstash 结果

"exception" => "Caused by: java.nio.file.NoSuchFileException"

您的 Logstach 环境中似乎设置了一些额外的选项。根据我的测试,我怀疑启用了 "verbose" 或 "ignore whitespace" 选项。此外,要排除 . 的任何其他问题(可以重新定义以匹配换行符),您可以使用明确的 [^\r\n] (任何不是 \r\n 的字符):

^(?!Caused\ by:)(?<exception>[^\r\n]*?Exception)
          ^^                 ^^^^^^^

转义的 space 将始终匹配单个正则 space。

注意:我在整个回答中都假设问题中显示并在下面重复的 2 个单独的日志行不包含换行符,并且已通过 logstash 中的多行编解码器插件进行处理或以某种方式删除。

TL;DR 使用负后视的解决方案

如果事后给它一个合适的锚点,消极的回头看就会起作用。查看这两行,这会很好地工作:

^(?<!Caused by: )java.*Exception

注意:它可能只是 ^(?<!Caused by: )j.*Exception,但我认为 java 使其更具可读性。

示例代码问题说明

给定正则表达式的问题:^(?<!Caused by: ).*?Exception(?<!^Caused by: ).*?Exception 是不情愿的 *? 量词,它允许某项匹配 0 次或多次。现在正如本 answer 中所解释的那样,正则表达式引擎从字符串的开头开始并向左移动以写入。尽可能少的字符数(因为它不愿意)只不过是引擎无法匹配 Exception 然后它逐渐尝试匹配 Exception 之前的任何内容(.)("backtracking") 左移书写。

因此,正则表达式引擎一直尝试一次再匹配一个字符(从左到右),直到在消耗完后找到 Exception。因此字符串

Caused by: java.nio.file.NoSuchFileException: fh-ldap-config/ at com.upplication.s3fs.util.S3Utils.getS3ObjectSummary(S3Utils.java:55) at com.upplication.s3fs.util.S3Utils.getS3FileAttributes(S3Utils.java:64)

确实匹配,因为引擎已经消耗了直到 Exception 的所有内容,并且 Caused by: 没有出现在 之前 此匹配。本质上,.*? 已经消耗了负面回顾正在寻找的 Caused by:

深入了解

要了解正则表达式引擎实际对 lookarounds 做了什么,我建议查看此 answer

我认为很容易被量词和环顾四周所吸引,作为一般规则,我认为环视需要 锚定 一些具体的东西(而不是 .) .为了理解我的意思,让我们看一下给定正则表达式与贪婪 * 量词的细微变化。正则表达式 ^(?<!Caused by: ).*Exception 也匹配带引号的字符串。

原因是贪婪的 * 限定符首先消耗整个字符串,然后从右向左回溯,如上面第一个链接的答案中所述。出于同样的原因(但从另一方面来说)一旦引擎匹配 Exception,它就会保存从字符串开头到 Exception 的所有内容。然后它会查看已消耗的内容,但未找到 Caused by: 并成功匹配字符串。

总结,作为一般规则

在使用贪婪或不情愿的量词时始终锚定环视。