如何在捕获组结束时重置整个比赛?

How to reset entire match at the end of a capturing group?

假设我有以下文本:

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

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

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

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

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

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

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

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

P.S。如果问题的标题不完全准确,我们深表歉意。

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

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

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

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

为了适应更多的选择,请确保使用此技术:尝试匹配尽可能接近字符串的开头,并且仅使用不必重新匹配的文本,否则,使用积极的先行捕获他们中的团体。