惰性量词和前瞻
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?://)
详情
(?>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 解决方案已经讨论了很多。 .
中涵盖了关于在哪里放置前瞻的确切疑问
我正在研究用于在 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?://)
详情
(?>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 解决方案已经讨论了很多。