在 Java 中提取没有条件前瞻的文本

Extract text without conditional lookahead in Java

我想使用 Java 正则表达式支持以 粗体 提取文本。

我可以使用条件先行来让它工作,正则表达式是

(\d{2})(\d{1,2})(\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})\s+(\S+)\s+(?(?=.*\d{4}-\d{1,2}-\d{1,2})([^\d{4}]*)|(.*))

但是,Java 模式 class 不支持条件先行。有没有办法重写正则表达式,使其与 Java 模式 class 一起使用?

160203 03:24:24 mysqld_safe 从 /var/lib/mysql2016-02-03 03:24:25 0 [警告] 具有隐式默认值的时间戳已弃用。请使用 --explicit_defaults_for_timestamp 服务器选项(更多详细信息请参阅文档)。2016-02-03 03:24:25 0 [注意] /opt/devenv/mysql/mysql-5.6.27-linux-glibc2.5-x86_64/bin/mysqld (mysqld 5.6.27) starting as process 29491 ...2016-02-03 03:24:25 29491 [注意] IPv6 可用。

160203 21:33:17 mysqld_safe 进程数 运行 现在:0

160203 21:33:17 mysqld_safe mysqld 重新启动2016-02-03 21:33:18 1125 [注意] 服务器主机名(绑定地址): '*'; port: 33062016-02-03 21:33:18 1125 [注意] IPv6可用。

您正在寻找的是经过调和的前瞻:

(?:(?!\d{4}-\d{1,2}-\d{1,2}).)*

这匹配直到(但不包括)下一个看起来像日期的东西,或下一行结束,以先到者为准。它这样做是在每个字符被使用之前检查它以确保它不是日期的第一个字符。要在 Java 中使用它:

Pattern p = Pattern.compile(
    "(?m)^(\d{2})(\d{1,2})(\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})\s+(\S+)\s+((?:(?!\d{4}-\d{1,2}-\d{1,2}).)*)");
Matcher m = p.matcher(s);
while (m.find()) {
    // matched text: m.group()
} 

(?m)^ 确保每个匹配项都从一行的开头开始。

我应该注意,这不等同于您的条件,但我认为这是您真正想要的。也许你觉得没问题,但考虑到这个假设的输入:

160203 21:33:17 mysqld_safe process1 restarted2016-02-03 21:33:18 1125

...您的正则表达式在 process1 中的 1 之前停止。

正则表达式中的 [^\d{4}]* 显然是要在下一个四字符序列处停止,但它实际上会停止任何不属于 {} 或一个数字。当然,它只会在 前瞻确定有一个提前的日期后才这样做。