【问题标题】:How to reset entire match at the end of a capturing group?如何在捕获组结束时重置整个匹配?
【发布时间】:2022-01-20 06:56:42
【问题描述】:

假设我有以下文本:

Yes: [x]
Yes: [  x]
Yes: [x  ]
Yes: [  x  ]
No: [x
No: x]

我对带有两个捕获组的regex 表达式感兴趣,如下所示:

  • $1:匹配括号[],其中包含xx 周围有可变数量的水平空间。我可以使用基于分支重置组的The fourth birdanswer

    • regex:(?|(\[)(?=\h*x\h*])|(?<=\[)\h*x\h*(]))

    • 导致:

  • $2:应该匹配包含在括号[] 中的x。为此,我可以使用非捕获组,结合肯定的后向和前瞻断言:

    • regex:(?:(?<=\[)\h*(x)(?=\h*]))

    • 导致:

问题是当我尝试通过OR 加入表达式时,第二个表达式不匹配任何内容。例如:

(?|(\[)(?=\h*x\h*])|(?<=\[)\h*x\h*(]))|(?:(?<=\[)\h*(x)(?=\h*]))

结果(即,请参阅 demo 并启用extended 标志以清楚起见):

我的直觉(即,可能不正确)是没有x 可以匹配第二个表达式,因为x 在第一个表达式中匹配(即组$0)。例如,将第二个表达式简化为 (?:(x))(即,参见 demo)将很好地匹配未包含在括号中的 x,如下所示。

因此,我认为我应该以某种方式从第一个表达式中重置组 $0 匹配项。所以我尝试在(]) 之前的第一个表达式中添加\K 元转义,但这并没有解决任何问题。

另外,我想尽可能地坚持(?|regex)|(?:regex)|... 的格式,因为我希望能够与其他组进一步扩展表达式。我正在使用Oniguruma regular expressionsPCRE 风味。您对如何实现这一点有任何想法吗?

附:如果问题的标题不完全准确,我们深表歉意。

【问题讨论】:

  • x 已被 \h*x\h*(]) 使用。
  • @WiktorStribiżew,我怀疑这可能是问题所在。是否有解决方法可以忘记 x 已被使用?我还尝试将\h*x\h* 也放在非捕获组中。
  • 参见regex101.com/r/v6zH2m/6,将分支重置组中的第二个替代项放在“取消使用”x的前瞻内。
  • @WiktorStribiżew,哦,这真是太聪明了!我想它可以工作,因为根据regular-expressions.info“lookaround 实际上匹配字符,但随后放弃匹配,只返回结果”?这真是太好了!
  • 您也可以在第一个备选方案中捕获组中的 x (?|(\[)(?=\h*(x)\h*])|(?&lt;=\[)\h*x\h*(])) 请参阅 regex101.com/r/Es5na6/1

标签: regex regex-lookarounds pcre regex-group


【解决方案1】:

主要问题是x 已被第一个替代方案中的\h*x\h*(]) 部分消耗,而第二个替代方案中的\h*(x) 无法重新匹配已消耗的部分。

如果您将分支重置组中的第二个替代项放在前瞻中,您可以“释放”x 以供第二个替代项捕获它:

(?|
  (\[) (?= \h* x \h* ] ) | (?<= \[ )(?= \h* x \h* (])) # <--- here
)
|
(?:
  (?<= \[ ) \h* (x) (?= \h* ] )
)

请参阅regex demo。注意(?=\h*x\h*(])) 部分:它现在是一个正向前瞻,仅在右侧立即检查其模式匹配,但不将匹配的文本放入匹配值缓冲区,也不推进正则表达式索引,以便后续子模式可以尝试将其模式与此文本进行匹配。

为了适应更多的选择,请确保使用这种技术:尝试匹配尽可能接近字符串的开头,并且只使用不需要重新匹配的文本,否则,使用正向前瞻和捕获组他们。

【讨论】:

  • 非常感谢您,也感谢您提供有关如何适应更多替代方案的提示!
猜你喜欢
  • 2019-11-01
  • 2021-06-21
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 2016-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多