正则表达式标记日志行

Regex to tokenize log line

我的日志行如下:

[2021-03-10 00:13:32.901] [DefaultDispatcher-worker-2 @coroutine#3] [DEBUG] [4231c006d9083a302fce59d5f0957226] [42c5ac3c0acfc68d] [GreeterImpl] Hello John

这是 [] 中的 6 个文本块,然后是其余部分。我正在寻找一个正则表达式来提取 [] 内以及末尾的文本。 [] 中的文本块可以为空。

我尝试了 (?:\[([^\[\]]*)\])+([^\[\]]+),但它只匹配 [] 中的第一个块。我也试过 (?:(?<=\[)[^\[\]]*(?=\]))+([^\[\]]+) 但不匹配。

FWIW,正则表达式将在 Java 中实现。

简短编辑: 这个稍微简单的正则表达式也可以工作:

(?:(?<=\[)[^\[\]]*)|(?:(?<=\])[^\[\]]*$)

我从你自己的评论中提取了它。

原回答如下。

TL;DR

(?:(?<=^\[| \[)[^\[\]]*)|(?:(?<=\] )[^\[\]]*$)

说明:两部分用|、“或”分隔。

  1. 第一部分,(?:(?<=^\[| \[)[^\[\]]*)匹配方括号内的内容。接近末尾的 [^\[\]]* 匹配最长可能的 运行 个既不是 [ 也不是 ] 的字符。 (?<=^\[| \[) 要求它在字符串开头和 [ [ 之前。最后我把整个东西放到一个非捕获组中以确保后视优先于 |.
  2. 第二部分 (?:(?<=\] )[^\[\]]*$) 匹配日志行末尾方括号外的内容(示例中的 Hello John)。这次非括号的运行前面必须有] ,后面有行尾

查看实际效果:

  1. On regex101 我建的地方

  2. 在Java:

    String logLine = "[2021-03-10 00:13:32.901]"
            + " [DefaultDispatcher-worker-2 @coroutine#3] [DEBUG]"
            + " [4231c006d9083a302fce59d5f0957226] [42c5ac3c0acfc68d]"
            + " [GreeterImpl] Hello John";
    
    Matcher m = Pattern
            .compile("(?:(?<=^\[| \[)[^\[\]]*)|(?:(?<=\] )[^\[\]]*$)")
            .matcher(logLine);
    while (m.find()) {
        System.out.println(m.group());
    }
    

输出为:

2021-03-10 00:13:32.901
DefaultDispatcher-worker-2 @coroutine#3
DEBUG
4231c006d9083a302fce59d5f0957226
42c5ac3c0acfc68d
GreeterImpl
Hello John

不同的想法:String.split()

    String[] tokens = logLine.split("\] \[|\] (?!\[)");
    assert tokens[0].startsWith("[") : logLine;
    tokens[0] = tokens[0].substring(1);

    for (String token : tokens) {
        System.out.println(token);
    }

输出与之前相同。

我在 ] [] 而不是 之后拆分 [ (最后一次拆分)。它使第一个 [ 完好无损,所以我必须单独删除它,这不太好。否则我发现它比其他解决方案更容易理解。

另一种选择是使用 \G 锚点来匹配开头的 [...] 部分,以及可选的第 2 组中的其余部分。

这样你就可以区分哪些部分在方括号之间,哪些部分在其余部分。

\G\[([^][]*)]\h+([^][]+$)?

模式匹配:

  • \G 断言位置在前一个匹配的末尾或在第一个匹配的字符串的开头
  • \[ 匹配 [
  • ( 捕获 组 1
    • [^][]* 匹配 0+ 次出现或除 []
    • 之外的任何字符
  • ) 关闭组 1
  • ]\h+ 匹配结尾 ] 和 1 个或多个水平空白字符
  • ( 捕获 第 2 组
    • [^][]+$ 匹配除 []
    • 之外的任何字符出现 1 次以上
  • )? 关闭组 2 并将其设为可选

Regex demo | Java demo

在 Java 中带有双反斜杠

String regex = "\G\[([^\]\[]*)]\h+([^\]\[]+$)?";