【问题标题】:Having difficulty in a understanding regex backtracking难以理解正则表达式回溯
【发布时间】:2018-07-10 16:41:55
【问题描述】:

当我遇到这个问题时,我正在浏览关于 SO 的正则表达式标记的问题,

需要一个 url 的正则表达式,该 url 以 domain.com/advertorials/ 开头

正则表达式应匹配以下场景,

  • domain.com/advertorials
  • domain.com/advertorials?test=true
  • domain.com/advertorials/
  • domain.com/advertorials/?test=true

    但不是这个,

  • domain.com/advertorials/version1?test=true

我想出了这个正则表达式advertorials\/?(?:(?!version)(.*))

这应该有效,但不适用于最后一种情况。查看 regex101.com 中的调试器, 我看到在匹配 's/' 之后,它逐个字符地匹配 'version' 单词并最终匹配,但由于这是负前瞻,因此条件失败。这是我在失败后回溯到's/'中的'/'之前而不是's/'之后的部分。

这是它应该如何工作的?谁能帮我理解? (这里是演示链接:https://regex101.com/r/ww3HR8/1)。

谢谢,

注意:人们已经针对这个问题给出了解决方案,我只是想知道为什么我的正则表达式会失败。

【问题讨论】:

    标签: regex regex-lookarounds


    【解决方案1】:

    正如您已经指出的那样,回溯机制负责这种现象。

    ? 量词,匹配 1 或 0 个重复的量化子模式让正则表达式引擎以两种方式匹配字符串:要么匹配量化子模式,要么继续匹配字符串与后续子模式。

    所以,advertorials/?(?!version)(.*)(我删除了多余的(?:...) 非捕获组),当应用于domain.com/advertorials/version1?test=true 时,匹配advertorials,然后匹配/,然后负前瞻检查是否,立即到当前位置的右边,有version子串。由于在/ 之后有version,正则表达式引擎返回并看到/? 模式可以匹配一个空字符串。因此,在advertorials 之后将重新应用前瞻检查。 advertorials后面没有version,返回匹配。

    通常的解决方案是使用所有格量词或原子组,但也有其他方法。

    例如

    advertorials\/?+(?!version)(.*)
                  ^^ 
    

    请参阅regex demo。在这里,\/?+ 匹配 1 或 0 个 / 字符,但是一旦匹配,引擎就无法返回并重新匹配该模式的字符串的一部分。

    或者,您可以在前瞻中包含/? 并将其放在/? 模式之前:

    advertorials(?!\/?version)\/?(.*)
    

    another regex demo

    如果您打算在advertorials 之后的任何位置禁止version,请使用

    advertorials(?!.*version)\/?(.*)
    

    yet another demo

    【讨论】:

    • 感谢您的详尽解释!
    【解决方案2】:

    使斜线可选意味着有一种方法可以在不违反约束的情况下进行匹配。如果有匹配的方法,正则表达式引擎总会找到它。

    当斜线后面跟着任何东西时,使斜线不可选。

    advertorials(?:/(?!version).*)?$
    

    顺便说一下,正则表达式本身不需要反斜杠转义(尽管一些宿主语言使用斜杠作为正则表达式分隔符,所以也许你需要把它放回去)。我还删除了一些多余的括号。

    【讨论】:

      【解决方案3】:

      原因:

      这个突出显示的部分是可选的 advertorials\/?(?:(?!version)(.*))

      因此也可以是advertorials(?:(?!version)(.*))
      匹配advertorials/version

      基本上,(?!version)(.*) 匹配 /version

      顺便说一句,这是正常的回溯 1 个字符。
      如果您已经修复了它,那么我们就完成了!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-24
        • 1970-01-01
        • 1970-01-01
        • 2017-09-24
        • 2016-10-07
        相关资源
        最近更新 更多