惰性量词和前瞻

Posted

技术标签:

【中文标题】惰性量词和前瞻【英文标题】:Lazy quantifier and lookahead 【发布时间】:2018-01-20 01:35:18 【问题描述】:

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

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

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

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

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

与惰性点星相比,这种技术没有任何优势

无论如何,这个解决方案就是回火点。这是我的下一次尝试:

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

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

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

其他解决方案已被广泛接受,但我首先希望了解这个解决方案。谢谢。

【问题讨论】:

这个问题太宽泛了。第二个“疑问”解释here。至于第一个,您只需要使用带有$肯定 前瞻作为替代方案((.*?)(?=https?:\/\/|$))。 .+? 匹配 1 个字符,由于它是惰性的,因此不必匹配更多。 “只有当 url 有效时我才需要匹配”是什么意思? 关于第一个疑问:我应该使用$ 这样惰性量词才能匹配到输入结束,对吗?为什么不暗示?我读了你关于 tempered greedy token 的回答,它肯定更清楚。仅当 url 不包含其他 http:// 时,我才需要匹配,而对于我当前的正则表达式,当 http:// 也包含时,我需要匹配。顺便说一句,谢谢你的回答。 看起来你想要(?>https?://\S+?/(?:(?!https?://).)*)(?!https?://)这样的东西。 你说的对。再次感谢您。 【参考方案1】:

你寻求的解决方案是

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

见regex demo

详情

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

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

缓和的贪婪令牌解决方案已经讨论了很多。 this answer 中涵盖了关于在何处放置前瞻的确切疑问。

【讨论】:

以上是关于惰性量词和前瞻的主要内容,如果未能解决你的问题,请参考以下文章

VST 前瞻和 setInitialDelay()

[正则]前瞻

视觉和前瞻性工程

1.6前瞻后顾

正则表达式忽略分组顺序匹配(前瞻后顾负前瞻负后顾的应用)

javascript 积极和消极的前瞻