惰性量词和前瞻
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://test
中n
后面没有这样的子串,所以返回以n
结尾的匹配,匹配成功。如果你不告诉正则表达式引擎匹配更多,或者匹配其他一些分隔符/模式,它不会。
缓和的贪婪令牌解决方案已经讨论了很多。 this answer 中涵盖了关于在何处放置前瞻的确切疑问。
【讨论】:
以上是关于惰性量词和前瞻的主要内容,如果未能解决你的问题,请参考以下文章