如何避免在正则表达式中使用不同的捕获组号?

How to avoid different capture group numbers in a regex?

我正在尝试在日志中捕获 IP 地址并在该地址为 0.0.0.0 时恢复到主机名。

以下是一些日志示例:

Foo bar ip=0.0.0.0 baz host=YOLO-PC foobar bazinga

在这种情况下,我想要 "YOLO-PC" 因为 IP 是 0.0.0.0

Foo bar ip=12.23.34.45 baz host=FOOBAR-PC foobar bazinga

在这种情况下,我想要12.23.34.45

这是我尝试过的:

ip=(?:0\.0\.0\.0|(\d+\.\d+\.\d+\.\d+)).*?host=(?(1).|(\S+))

有效,但是当 IP 为 0.0.0.0 时,它会创建第二个组,它后面的程序无法获取组 #2,只能获取组 #1。

我该怎么做?全部放在一个组里?有更好的解决方案吗?

结果中的组数等于正则表达式中的 ( ) 组数。您引用它们的顺序是左括号在正则表达式中出现的顺序。某些组可能不匹配且为空。

所以在你的情况下,你总是有两个组。第 1 组是非零 ip,第 2 组是主机名。如果 IP 为 0.0.0.0,则组 1 将为空。如果不是,则第 2 组将为空。

你不能只检查你的代码哪一组是空的,然后使用另一组吗?

从你的问题中不清楚你正在处理哪种 environment/language/regex 口味。但是 PCRE 正则表达式实际上让你用 (?|some(capture)|another(capture)) 语法来做到这一点:

ip=(?|0\.0\.0\.0.*?host=(\S+)|(\d+\.\d+\.\d+\.\d+))

您可以从 debuggex visualisation that both groups are numbered 1. And on regex101 中看到右侧的捕获。

或者(如果您不使用 PCRE),我想您可以这样做。它不那么严格,但适用于大多数引擎。您当前的正则表达式对 IP 格式不是特别严格(允许大于 255 的数字等),所以这对您来说可能不是问题。

ip=(?:0\.0\.0\.0.*?host=)?(\S+)

Debuggex Demo

使用交替,尝试从左到右:

(?<=ip)(?!0.0.0.0)\S+|(?<=host=)\S+

demo

由于使用环顾四周,这仅匹配您的目标输入。消极的展望决定不使用 ip 如果它全部为零。

只选择 第一个 匹配项。