Ruby 正则表达式中的可选命名组

Optional named group in Ruby RegExp

我正在使用一个插件来解析发送到 fluentd 的 nginx 日志条目,并尝试对其进行更改,以便它可以选择支持另一个字段。 这是当前用于解析 nginx 日志条目的 REGEXP config_set_default :expression, %q{/^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/}

我尝试像这样将新字段添加到 REGEXP - config_set_default :expression, %q{/^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)"(?<http_x_forwarded_for>[^ ]*)?)?$/}

这个 REGEXP 可以解析日志条目是否有新字段,但仍然为新字段创建一个命名组,这使得针对插件的现有测试运行中断。

我想知道是否有某种方法可以指示 REGEXP 如果该组的值存在,它应该添加命名组,否则省略该组。

这里有 2 个日志条目的例子,有和没有新字段(分别)-
127.0.0.1 192.168.0.1 - [28/Feb/2013:12:00:00 +0900] "GET / HTTP/1.1" 200 777 "-" "Opera/12.0"
127.0.0.1 192.168.0.1 - [28/Feb/2013:12:00:00 +0900] "GET / HTTP/1.1" 200 777 "-" "Opera/12.0" -

您需要在最后一个字段模式之后添加 (?:\s+(?<http_x_forwarded_for>\S+))? 可选 non-capturing 组。这意味着命名的捕获组应该在一个可选的 non-capturing 中,并且 \s+ 应该放在它之前以考虑字段之前的任何 1+ 个空白字符。

使用

^(?<remote>\S*) (?<host>\S*) (?<user>\S*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^"]*?)(?:\s+\S*)?)?" (?<code>\S*) (?<size>\S*)(?: "(?<referer>[^"]*)" "(?<agent>[^"]*)"(?:\s+(?<http_x_forwarded_for>\S+))?)?$

参见regex demo

请注意,我将 [^ ] 替换为 \S,这样可以更自然地将除空白字符之外的字符与正则表达式匹配。