.+?\.([\w-]*?\.(?:ru|ua|com\.ua|com|net|info))$
此答案仍然使用原始问题正在查看的特定域名。由于某些 TLD(顶级域)中有一个句点,理论上您可以拥有一个包含多个子域的列表,如果它适用于您的数据集,则在正则表达式中将 TLD 列入白名单是一个好主意。当前的两个答案(从 2013 年开始)都无法正确处理“xx.bb.prontube.ru”和“srfsf.jwbefw.com.ua”之间的区别。
下面简要解释了为什么这个 psnig 的原始正则表达式不能按预期工作:
+ 是贪婪的。
.+ 将在行尾一直拉到右边,捕获所有内容,
然后从这里向后(向左)寻找匹配项:
(ru|ua|com\.ua|com|net|info)
使用 srfsf.jwbefw.com.ua 正则表达式引擎将首先无法匹配a,
然后它将令牌向左移动一位以查看“ua”
此时,正则表达式(第二个选项)中的ua 是匹配的。
引擎不会继续寻找“com.ua”,因为“.ua”满足了该要求。
Niet the Dark Absol 的回答告诉正则表达式“懒惰”
.+? 将匹配任何字符(至少一个),然后尝试查找正则表达式的下一部分。如果失败,它将推进标记,.+ 再匹配一个字符,然后再次评估正则表达式的其余部分。
.+?最终会消耗:srfsf.jwbefw在匹配句点之前,然后匹配com.ua。
但是? 的暗示也会产生问题。
添加问号会首先使 .+ 变得懒惰,但随后会导致 group1 匹配 bb.prontube.ru 而不是 prontube.ru
这是因为 bb 之后的第一个句点将匹配,然后组 1 内的 (.*?) 将匹配 bb.prontube。 \.(ru|ua|com\.ua|com|net|info))$ 之前匹配 .ru
为避免这种情况,请将第三组从(.*?) 更改为([\w-]*?),这样它就不会捕获。只有字母和数字,或破折号。
生成的正则表达式:
.+?\.(([\w-])*?\.(ru|ua|com\.ua|com|net|info))$
请注意,您不需要捕获除第一个组之外的任何组。添加 ?: 使 TLD 选项不被捕获。
上次更改:
.+?\.([\w-]*?\.(?:ru|ua|com\.ua|com|net|info))$