【问题标题】:Lazy regex doesn't work as expected C#懒惰的正则表达式不能按预期工作 C#
【发布时间】:2011-03-06 04:54:19
【问题描述】:

我有以下正则表达式:a?\W*?b 我有一个字符串,.! ,b
在搜索匹配项时,我得到,.! ,b,但不像我预期的那样只是b。这是为什么?如何修改正则表达式以获得我需要的内容?
谢谢您的帮助。

【问题讨论】:

  • 请提供一些示例,说明您想做什么和不想做什么。最好不要过度简化您的正则表达式(下面的评论表明您实际上正在做其他事情),否则解决方案也可能过于简单。

标签: c# regex regex-greedy


【解决方案1】:

regex 称为贪婪或非贪婪是错误的。您可以在整个正则表达式中使用非贪婪量词,但正如您发现的那样,它仍会尽可能早地尝试开始匹配。同样,仅使用贪婪量词的正则表达式不能保证返回 longest 可能的匹配。例如,

Regex.Match("foo bar", @"\w+ (?:b|bar)")

...返回foo b,因为交替选择第一个可行的替代方案,即使后面的替代方案会导致更长的匹配。 (请注意,我说的是 Perl 派生的正则表达式风格,如 .NET;一些风格,如 awkegrep,确实支持尽可能长的匹配。但是,因为这些风格没有非greedy 量词,greedy 不仅仅是默认模式,它是 only 模式。)

简而言之,没有贪婪或非贪婪的正则表达式,只有贪婪或非贪婪的量词。

【讨论】:

    【解决方案2】:

    惰性表达式仅从右侧开始惰性,即通过删除右侧的字符使其尽可能短,但不会删除左侧的字符。

    为了让匹配稍后开始,你需要一个贪婪的表达式来吞下你不想匹配的字符。

    或者,正如 Tim 所示,您可以通过仅匹配第一个字符和以下分隔符(如果第一个字符存在)来使匹配稍后开始。

    【讨论】:

      【解决方案3】:

      您的示例没有说明为什么a? 是您的正则表达式的一部分,而是仅匹配看起来像,.! ,b 的字符串中的b,您可以使用像(?=\W*?)b 这样的lookbehind。

      这匹配b,前面有一个“非单词字符”零次和无限次(尽可能少)

      如果您只想匹配 ab 等字符串,例如 a,.! ,b,则必须使用捕获组:(a?)\W*?(b) 其中第一组将保存 a(如果存在)和组2b

      【讨论】:

        【解决方案4】:

        懒惰的量词在这里对你想要的没有帮助。让我们看看发生了什么。

        正则表达式引擎从字符串的开头开始。首先尝试匹配a。不能,但没问题,因为a 是可选的。

        然后,有一个懒惰的\W*?,所以正则表达式引擎会跳过它但记住当前位置。

        然后它会尝试匹配b。它不能,所以它回溯并成功地将,\W*? 匹配。然后它继续尝试匹配b(因为惰性量词)。它仍然不能并再次回溯。这会重复几次,直到正则表达式引擎最终到达b。现在匹配已完成 - 正则表达式引擎宣布成功。

        所以正则表达式按规定工作 - 只是不符合预期。现在的问题是:您想要正则表达式到底做什么?

        例如,如果你真正想要的是:

        单独匹配b,除非它前面有a和一些非单词字符,在这种情况下匹配从ab的所有字符,然后使用

        b|a\W*b
        

        【讨论】:

        • 如果我有以下正则表达式 'a?\W*?b?\W*?c?\W*?d?' 怎么办?我希望任何非空匹配都以字母开头并以字母结尾
        • 执行您刚刚编写的操作的正则表达式可能是^([a-z].*[a-z]$|)$。匹配以字母开头和结尾的内容,或匹配空字符串。如果您也想匹配大写字母,请使用 RegexOptions.IgnoreCase。如果您还想允许非 ASCII 字母,请使用 \p{L} 而不是 [a-z]
        • +1,很好的解释......我今天学到了一些关于正则表达式的东西:)
        【解决方案5】:

        a?“我想要 a 的零个或一个实例” - 这是因为有零个实例而满足,然后是

        \W*“我想要零个或多个非单词字符”,通过标点和空格字符来满足,最后

        b“匹配一个字母 b,它确实如此。所以你的整个字符串都满足正则表达式。

        如果您在任何人提出可能的解决方案之前提供更多可能输入的示例,这会有所帮助。

        【讨论】:

        • 你的解释是忽略了懒惰的量词*?...为什么在这里不起作用?
        • \W*?是懒惰的。所以它应该包含尽可能少的符号。这里最少的符号数量是 0。
        【解决方案6】:

        您的正则表达式匹配整个字符串,如下所示:

        1. 一个,零次或一次重复(在本例中为“”)
        2. 任何非字母数字字符,任何重复次数,尽可能少(在本例中为“,.!”)
        3. b

        在您的情况下,正则表达式匹配整个字符串,因此不会只找到 b(它找不到同一部分的多个匹配项)。

        如果您在字符串中搜索 ',.! ,db' 它会找到 b。

        【讨论】:

        • 我可以告诉你正在使用 Expresso,我的屏幕上有完全相同的描述;)
        • 是的 - 认为这是很好的描述,所以我没有费心重写:-)
        【解决方案7】:

        例如,以下可能有效:(a\W*)?b

        要更好地了解什么可以解决您的问题,您应该提供更多示例。

        【讨论】:

        • 其实原来的正则表达式是 'a?\W*?b?\W*?c?'我希望任何匹配都不包含非字母 (\W) 符号,无论是从开头还是结尾。
        • 您能否澄清一下(一些示例怎么样?)并将其放入您最初的问题中,而不是放在 cmets 中更难找到的某个地方?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-02-22
        • 2018-06-04
        • 2011-03-09
        • 2014-04-28
        相关资源
        最近更新 更多