正则表达式:当且仅当它包含一些后续参数时才传递查询字符串?

Regex: pass a query string if and only if it includes some subsequent parameters?

我正在尝试使用 PaperTrail 的过滤器日志工具通过 RegEx 过滤掉特定路径。我的日志字符串可能类似于以下之一:

不应通过且不会被记录

Sep 03 10:12:40 lastmingear heroku/router:  at=info method=GET path="/orders/SOME_ID?key=USER_KEY" host=www.lastmingear.com...

应该通过,并被记录

Sep 03 10:12:40 lastmingear heroku/router:  at=info method=GET path="/orders/SOME_ID?key=USER_KEY&log=true" host=www.lastmingear.com...

唯一的区别是我希望它被记录的路径有一个额外的参数log=true。所以 RegEx 语句应该口头阅读,例如:

IF a key=USER_KEY is provided, then do NOT pass into logs UNLESS there is also a log=true

您可以使用正则表达式,但将查询字符串与这样的模式进行匹配通常被认为是一种不好的做法。如果参数的顺序不同怎么办?如果它们之间还有其他参数怎么办?如果它们是 URL 编码的怎么办?

相反,您可以考虑解析查询字符串并分析键值对:

require 'uri'

def log?(log_line)
  path = log_line[/path="([^"]+)"/, 1]
  uri = URI(path)
  params = URI.decode_www_form(uri.query).to_h
  not params['key'] or params['log'] == 'true'
end

更新:这是一个需要解决的棘手的正则表达式问题,因为没有真正的方法来表达 if-this-then-that-or-etc。在正则表达式中。您可以使用断言,但它们只能帮助您到此为止。您基本上必须枚举所有要传递的模式。我想强调的是,这是相当脆弱的,您需要随着时间的推移密切关注它,看看模式是否有任何差异。

此模式将 /orders 路由的日志行与数字订单号和可选查询字符串相匹配。如果提供了查询字符串,它必须与提供的模式之一相匹配。如果提供了数字键编号,则 log 必须为真。

/path="\/orders\/\d+
  (?:\?
    (?:(?!(?<=[?&])key=\d+(?=[&"])).)*?
    |(.+?&)?log=true(&.+?)?
  )?
"/x

虽然我更喜欢@mwp 给出的答案,但以下正则表达式有什么问题:

/path="[^"]+?\&log=true.*?"/

以非贪婪方式匹配所有非引号,直到找到 &log=true 后跟任何非贪婪方式然后是结束引号。