【问题标题】:Surprising, but correct behavior of a greedy subexpression in a positive lookbehind assertion积极的后向断言中贪婪子表达式的令人惊讶但正确的行为
【发布时间】:2021-03-02 19:59:03
【问题描述】:

注意

  • 观察到的行为是正确的,但起初可能令人惊讶;对我来说是这样,我认为对其他人来说可能也是如此——尽管对于那些非常熟悉正则表达式引擎的人来说可能不是。

  • 重复建议的重复,Regex lookahead, lookbehind and atomic groups,包含关于环视断言的一般信息,但没有解决手头的具体误解,如更详细讨论的那样在下面的 cmets 中。


使用 greedy,根据定义,positive look-behind assertion 内的 variable-width 子表达式可能会表现出令人惊讶的行为。

为方便起见,示例使用 PowerShell,但该行为通常适用于 .NET 正则表达式引擎:

这个命令按我的直觉工作:

# OK:  
#     The subexpression matches greedily from the start up to and
#     including the last "_", and, by including the matched string ($&) 
#     in the replacement string, effectively inserts "|" there - and only there.
PS> 'a_b_c' -replace '^.+_', '$&|'
a_b_|c

以下使用肯定的后向断言(?<=...) 的命令看似等效,但不是

# CORRECT, but SURPRISING:
#   Use a positive lookbehind assertion to *seemingly* match
#   only up to and including the last "_", and insert a "|" there.
PS> 'a_b_c' -replace '(?<=^.+_)', '|'
a_|b_|c  # !! *multiple* insertions were performed

为什么不等价?为什么要执行多次插入?

【问题讨论】:

  • @WiktorStribiżew 重新发布相同的信息而不解决相反的问题是没有帮助的。下面答案中的 cmets 解释了为什么您的链接没有帮助。您这次发布的附加链接也无济于事,可以通过查找术语“可变宽度”、“可变长度”和“贪婪”来轻松验证 - this 问题是关于 - 那里:你不会找到他们。
  • 只是为了避免未来的读者可能会浪费精力,并平衡上面评论中的喊叫声:所谓的重复一般描述了外观的行为-围绕断言。他们没有解决这个问题的具体误解。虽然您可以假设从链接的帖子中推断解释,但这样的推断远非显而易见。 只有下面的答案提供了具体的、(希望)清晰的解释
  • 这能回答你的问题吗? Regex lookahead, lookbehind and atomic groups

标签: .net regex regex-lookarounds regex-greedy


【解决方案1】:

tl;dr

  • 后视断言中,贪婪子表达式实际上表现非贪婪(在全局匹配除了贪婪),因为考虑到输入字符串的每个前缀字符串

我的问题是 我没有考虑到,在后向断言中,必须检查输入字符串中的每个字符位置是否有 前面的文本到那时 以匹配后向断言中的子表达式。

这与 PowerShell 的 -replace 运算符执行的始终全局替换(即执行 所有 个可能的匹配)相结合,导致 多个 插入:

也就是说,当考虑当前正在考虑的字符位置左侧的文本时,贪婪的锚定子表达式^.+_ 合法匹配两次:

  • 首先,当a_ 是左边的文本时。
  • a_b_ 是左边的文字时。

因此,两个插入了|


相比之下,没有后向断言,根据定义,贪婪表达式^.+_只匹配一次,直到最后一个@ 987654330@,因为它只应用于整个输入字符串

【讨论】:

  • 这是known lookaround behavior。无需重复。这也是Regex FAQ 的一部分。
  • @WiktorStribiżew 重新链接您的链接:FAQ(无疑是一个很好的通用资源)仅链接到第一个链接的答案,这是关于 不支持可变宽度模式 Python 中的后向断言。相比之下,this 问题正是关于 variable-width 模式的,而正是这种可变宽度的性质导致了我的问题中表现出的误解。常见问题解答中对可变宽度后视的唯一引用是 this answer,它只是说明 .NET 确实支持它们。
  • 简而言之:您发布的链接中没有描述的行为 - 没有以任何有意义的方式来消除手头的具体误解。这个答案现在确实描述了它,希望它也能消除其他人的误解。
猜你喜欢
  • 2021-01-12
  • 2019-10-05
  • 1970-01-01
  • 2015-08-25
  • 2012-07-27
  • 1970-01-01
  • 1970-01-01
  • 2012-09-12
  • 2020-01-11
相关资源
最近更新 更多