惰性量词和前瞻

Lazy quantifier and lookahead

我正在研究用于在 C# 中验证 urls 的正则表达式。现在,我需要的正则表达式不能匹配其他 http://,而是匹配 url 中的第一个。这是我的第一次尝试:

(https?:\/\/.+?)\/(.+?)(?!https?:\/\/)

但是这个正则表达式不起作用(甚至删除 (?!https?:\/\/))。以这个输入字符串为例:

http://test.test/notwork.http://test

这是我的第一个疑问:为什么捕获组(.+?)不匹配notwork.http://test?惰性量词应该匹配尽可能少的次数,但为什么不匹配到最后呢?在这种情况下,我肯定遗漏了一些东西(首先我认为它可能与回溯有关,但我不认为是这种情况),所以我阅读 this 并找到了解决方案,即使我不确定是最好的,因为它说

This technique presents no advantage over the lazy dot-star

总之,那个解决方案就是锤炼点。这是我的下一次尝试:

(https?:\/\/.+?)\/((?:(?!https?:\/\/).)*)

现在:这个正则表达式可以正常工作,但不是我想要的方式。 只有当 url 有效时我才需要匹配。

顺便说一句,我想我还没有完全理解新的正则表达式在做什么:为什么负前瞻停留在 . 之前而不是之后? 所以我尝试将它移到 . 之后,它似乎与 url 匹配,直到它找到第二个 http 之前的倒数第二个字符。回到更正后的正则表达式,我的假设是负前瞻实际上是在尝试检查正则表达式已经读取的 . 之后的内容,对吗?

其他解决方案也很受欢迎,但我首先更愿意了解这个。谢谢。

您寻求的解决方案是

(?>https?://\S+?/(?:(?!https?://).)*)(?!https?://)

regex demo

详情

  • (?>https?://\S+?/(?:(?!https?://).)*) - 匹配的原子组(不允许回溯到其子模式)
    • https?:// - http://https://
    • \S+? - 任何 1 个或多个非空白字符,尽可能少,直到第一个...
    • / - / 符号后跟...
    • (?:(?!https?://).)* - 不开始 http://https:// 字符序列的零个或多个字符(尽可能多)。
  • (?!https?://) - 如果在当前位置右侧紧邻 http://https://,则否定前瞻会导致匹配失败。

(https?:\/\/.+?)\/(.+?)(?!https?:\/\/) 不起作用,因为 .+? 模式正在匹配 lazily,即它获取它找到的第一个字符,然后让后续的子模式比赛。随后的子模式是一个否定的 loolahead,只有在当前位置右侧没有 http://https:// 的情况下才会匹配失败。由于http://test.test/notwork.http://test中的n后没有子串,所以返回以n结尾的匹配,匹配成功。如果你不告诉正则表达式引擎匹配更多,或者最多匹配一些其他 delimiter/pattern,它不会。

tempered greedy token 解决方案已经讨论了很多。 .

中涵盖了关于在哪里放置前瞻的确切疑问