什么是正则表达式,它将匹配没有子域的有效域名?

时间:2012-04-24 22:02:56

标签: regex validation domain-name

首先抱歉第10,000次RegEx问题,

我意识到还有其他与域相关的问题,但正则表达式要么无法正常运行,要么太复杂,要么对于具有子域,协议和文件路径的网址。

我更简单,我需要验证域名:

google.com

stackoverflow.com

这是一个最新形式的域名 - 甚至不是像www。

这样的子域名
  1. 字符应该只是 a-z | A-Z | 0-9 期间(。)和破折号( - )
  2. 域名部分不应以短划线( - )开头或结尾(例如-google-.com)
  3. 域名部分的长度应介于1到63个字符之间
  4. 目前,扩展名(TLD)可以是#1规则下的任何内容,我可以稍后对列表进行验证,但它应该是1个或多个字符
  5. 编辑:TLD显然是2-6个字符

    否。 4修订版: TLD实际上应该标记为“子域名”,因为它应该包含像.co.uk这样的东西 - 我想可能的唯一验证(除了检查列表之外)将是'在第一个点之后应该是规则#1下的一个或多个字符

    非常感谢,相信我,我确实尝试过!

22 个答案:

答案 0 :(得分:70)

我知道这是一个旧帖子,但是这里的所有正则表达式都缺少一个非常重要的组件:对IDN域名的支持。

IDN domain names以xn--开头。它们在域名中启用扩展的UTF-8字符。例如,你知道“♡.com”是一个有效的域名吗?是的,“爱心点com”!要验证域名,您需要让http://xn--c6h.com/通过验证。

注意,要使用此正则表达式,您需要将域转换为小写,并使用IDN库来确保将域名编码为ACE(也称为“ASCII兼容编码”)。一个好的库是GNU-Libidn。

idn(1)是国际化域名库的命令行界面。以下示例将UTF-8中的主机名转换为ACE编码。然后,生成的网址https://nic.xn--flw351e/可以用作ACE编码的等效https://nic.谷歌/

  $ idn --quiet -a nic.谷歌
  nic.xn--flw351e

这个神奇的正则表达式应涵盖大多数域名(尽管我确信有许多我错过的有效边缘案例):

^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.(xn--)?([a-z0-9\-]{1,61}|[a-z0-9-]{1,30}\.[a-z]{2,})$

选择域验证正则表达式时,您应该看到域是否与以下内容匹配:

  1. xn--stackoverflow.com
  2. stackoverflow.xn - COM
  3. stackoverflow.co.uk
  4. 如果这三个域名没有通过,那么您的正则表达式可能不允许合法域名!

    查看The Internationalized Domain Names Support page from Oracle's International Language Environment Guide了解详情。

    请在此处试用正则表达式:http://www.regexr.com/3abjr

    ICANN 保留a list of tlds that have been delegated,可用于查看IDN域的一些示例。


    编辑:

     ^(((?!-))(xn--|_{1,1})?[a-z0-9-]{0,61}[a-z0-9]{1,1}\.)*(xn--)?([a-z0-9\-]{1,61}|[a-z0-9-]{1,30}\.[a-z]{2,})$
    

    此正则表达式将停止在主机名末尾标记为有效的域名为“ - ”的域。此外,它允许无限制的子域。

答案 1 :(得分:45)

我的RegEx是下一个:

^[a-zA-Z0-9][a-zA-Z0-9-_]{0,61}[a-zA-Z0-9]{0,1}\.([a-zA-Z]{1,6}|[a-zA-Z0-9-]{1,30}\.[a-zA-Z]{2,3})$

i.oh1.me wow.british-library.uk

<强> UPD

这是更新后的规则

^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z]{2,3})$

Regular expression visualization

https://www.debuggex.com/r/y4Xe_hDVO11bv1DV

现在检查域名标签开头或结尾的-_

答案 2 :(得分:38)

嗯,根据你的具体要求,非常简单比它看起来有点偷偷摸摸(见评论):

/^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/

但请注意,这将拒绝许多有效的域名。

答案 3 :(得分:13)

只是一个小小的修正 - 最后一部分应该达到6.因此,

^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$

最长TLD为museum(6个字符) - http://en.wikipedia.org/wiki/List_of_Internet_top-level_domains

答案 4 :(得分:13)

我打赌:

^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$

<强>解释

域名是根据细分构建的。这是一个部分(最终除外):

[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?

它可以有1-63个字符,不会以&#39; - &#39;开始或结束。

现在追加&#39;。&#39;到它并重复至少一次:

(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+

然后附加最终段,长度为2-63个字符:

[a-z0-9][a-z0-9-]{0,61}[a-z0-9]

在此测试: http://regexr.com/3au3g

答案 5 :(得分:12)

这个答案适用于域名(包括服务RR),而不是主机名(如电子邮件主机名)。

^(?=.{1,253}\.?$)(?:(?!-|[^.]+_)[A-Za-z0-9-_]{1,63}(?<!-)(?:\.|$)){2,}$

基本上是mkyong's answer,另外:

  • 最大长度为255个八位字节,包括长度前缀和空根。
  • 允许跟踪&#39;。&#39; for explicit dns root。
  • 允许领先&#39; _&#39;对于服务域RR,(错误:不对_标签强制执行15个字符最大值,也不要求至少一个域超过服务RR)
  • 匹配所有可能的TLD。
  • 不捕获子域名标签。

按部件

Lookahead,使用可选的尾随文字限制^ $到253个字符之间的最大长度&#39;。&#39;

(?=.{1,253}\.?$)

Lookahead,下一个角色不是&#39; - &#39;并且没有&#39; _&#39;在下一个&#39;之前跟随任何字符。&#39;。也就是说,强制标签的第一个字符不是&#39; - &#39;并且只有第一个字符可能是&#39; _&#39;。

(?!-|[^.]+_)

每个标签允许的字符数在1到63之间。

[A-Za-z0-9-_]{1,63}

Lookbehind,以前的角色不是&#39; - &#39;。也就是说,强制标签的最后一个字符不是&#39; - &#39;。

(?<!-)

强迫一个&#39;。&#39;在每个标签的末尾,除了最后一个标签,它是可选的。

(?:\.|$)

大部分从上面合并,这需要至少两个域级别,这不是很正确,但通常是合理的假设。如果您想允许TLD或不合格的相对子域(例如,localhost,myrouter,to。),请从{2,}更改为+。

(?:(?!-|[^.]+_)[A-Za-z0-9-_]{1,63}(?<!-)(?:\.|$)){2,}

Unit tests表达此表达式。

答案 6 :(得分:11)

接受的答案不适合我,试试这个:

  

^(( - )[A-ZA-Z0-9 - ] {1,63}(小于?! - ?!)\)+ [A-ZA-Z] {2,6-} $ < / p>

访问此Unit Test Cases进行验证。

答案 7 :(得分:8)

感谢您在其他答案中指出域名验证解决方案的正确方向。域名可以通过各种方式进行验证。

如果您需要以人类可读形式验证 IDN 域,则正则表达式\p{L}会有所帮助。这允许匹配任何语言的任何字符。

请注意最后一部分也可能包含连字符!由于punycode编码,Chineese名称可能在tld中具有unicode字符。

我已经找到了解决方案,例如:

  • google.com
  • masełkowski.pl
  • maselkowski.pl
  • m.maselkowski.pl
  • www.masełkowski.pl.com
  • xn--masekowski-d0b.pl
  • 中国互联网络信息中心。中国
  • XN - fiqa61au8b7zsevnm8ak20mc4a87e.xn - fiqs8s

正则表达式是:

^[0-9\p{L}][0-9\p{L}-\.]{1,61}[0-9\p{L}]\.[0-9\p{L}][\p{L}-]*[0-9\p{L}]+$

Check and tune here

注意:此正则表达式非常宽松,当前域名允许使用字符集。

更新:更简化,因为a-aA-Z\p{L}\p{L}相同

注意2:唯一的问题是它会匹配其中带有双点的域......,如masełk..owski.pl。如果有人知道如何解决这个问题,请改进。

答案 8 :(得分:5)

^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,7}$

[域名 - 小写字母和仅0-9] [可以有连字符] + [TLD - 仅限小写,必须在2到7个字母之间]
http://rubular.com/非常适合测试正则表达式!
编辑:正如Dan Caddigan指出的那样,为'.rentals'更新了TLD最多7个字符。

答案 9 :(得分:5)

还没有足够的回复评论。为了回应paka的解决方案,我发现我需要调整三个项目:

  • 由于破折号被解释为范围(如&#34; 0-9&#34;)
  • ,因此移动了破折号和下划线
  • 为包含多个子域的域名添加了句号
  • 将TLD的潜在长度延长至13

在:

^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z]{2,3})$

后:

^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][-_\.a-zA-Z0-9]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,13}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z]{2,3})$

答案 10 :(得分:2)

^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]+(\.[a-zA-Z]+)$

答案 11 :(得分:2)

对于新gTLD

/^((?!-)[\p{L}\p{N}-]+(?<!-)\.)+[\p{L}\p{N}]{2,}$/iu

答案 12 :(得分:1)

^((localhost)|((?!-)[A-Za-z0-9-]{1,63}(?<!-)\.)+[A-Za-z]{2,253})$

谢谢@mkyong作为答案的基础。我修改了它以支持更长的可接受标签。

此外,“localhost”在技术上是一个有效的域名。我将修改此答案以适应国际化域名。

答案 13 :(得分:1)

很简单,很宽容。它将具有误报,例如 -notvalid.at-all ,但不会有误报。

/^([0-9a-z-]+\.?)+$/i

确保它具有字母数字和破折号的序列,并以点结尾,并在其后跟随任意数量的此类序列。

我喜欢这个正则表达式的地方:它简短(也许是这里最短),易于理解,并且足以验证客户端的用户输入错误。

答案 14 :(得分:1)

这是完整的代码示例:

<?php
function is_domain($url)
{
    $parse = parse_url($url);
    if (isset($parse['host'])) {
        $domain = $parse['host'];
    } else {
        $domain = $url;
    }

    return preg_match('/^(?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63}$/', $domain);
}

echo is_domain('example.com'); //true
echo is_domain('https://example.com'); //true
echo is_domain('https://.example.com'); //false
echo is_domain('https://localhost'); //false

答案 15 :(得分:0)

  

^ [A-ZA-Z0-9] [ - α-ZA-Z0-9] + [A-ZA-Z0-9] [AZ] {2,3}([AZ] {2,。。 3})?([AZ] {2,3})?$

有效的例子:

stack.com
sta-ck.com
sta---ck.com
9sta--ck.com
sta--ck9.com
stack99.com
99stack.com
sta99ck.com

它也适用于扩展程序

.com.uk
.co.in
.uk.edu.in

不起作用的示例:

-stack.com

即使使用最长的域扩展名".versicherung"

,它也能正常工作

答案 16 :(得分:0)

正如已经指出的,从实际意义上讲子域并不明显。 We use此正则表达式可验证野外出现的域。它涵盖了我所知道的所有实际用例。欢迎新的。根据{{​​3}},它避免了非捕获组和贪婪匹配。

^(?!.*?_.*?)(?!(?:[\d\w]+?\.)?\-[\w\d\.\-]*?)(?![\w\d]+?\-\.(?:[\d\w\.\-]+?))(?=[\w\d])(?=[\w\d\.\-]*?\.+[\w\d\.\-]*?)(?![\w\d\.\-]{254})(?!(?:\.?[\w\d\-\.]*?[\w\d\-]{64,}\.)+?)[\w\d\.\-]+?(?<![\w\d\-\.]*?\.[\d]+?)(?<=[\w\d\-]{2,})(?<![\w\d\-]{25})$

证明和解释:our guidelines

验证域时,有两种方法可供选择。

按书中的FQDN匹配(理论上的定义,在实践中很少遇到):

实用/保守的FQDN匹配(实践定义,在实践中应得到预期和支持):

  • 按书进行匹配,但具有以下例外/补充内容
  • 有效字符:[a-zA-Z0-9.-]
  • 标签不能以连字符开头或结尾(根据RFC-3696/2RFC-952
  • TLD的最小长度为2个字符,根据当前现有记录的最大长度为24个字符
  • 不匹配尾随点

答案 17 :(得分:0)

  • ^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,}\.?((xn--)?([a-z0-9\-.]{1,61}|[a-z0-9-]{0,30})\.[a-z-1-9]{2,})$

将在编码后验证诸如яндекс.рф之类的域。

https://regex101.com/r/Hf8wFM/1-沙箱

答案 18 :(得分:0)

以下正则表达式提取给定域的子,根和tld:

^(?<domain>(?<domain_sub>(?:[^\/\"\]:\.\s\|\-][^\/\"\]:\.\s\|]*?\.)*?)(?<domain_root>[^\/\"\]:\s\.\|\n]+\.(?<domain_tld>(?:xn--)?[\w-]{2,7}(?:\.[a-zA-Z-]{2,3})*)))$

针对以下域进行了测试:

* stack.com
* sta-ck.com
* sta---ck.com
* 9sta--ck.com
* sta--ck9.com
* stack99.com
* 99stack.com
* sta99ck.com
* google.com.uk
* google.co.in

* google.com
* masełkowski.pl
* maselkowski.pl
* m.maselkowski.pl
* www.masełkowski.pl.com
* xn--masekowski-d0b.pl
* xn--fiqa61au8b7zsevnm8ak20mc4a87e.xn--fiqs8s

* xn--stackoverflow.com
* stackoverflow.xn--com
* stackoverflow.co.uk

答案 19 :(得分:0)

我做了以下操作,以简单地获取域和协议。 例: https://www.facebook.com/profile/user/ ftp://182.282.34.337/movies/M

使用以下正则表达式模式: [a-zA-Z0-9] +://.*?/

将为您提供输出: https://www.facebook.com/ ftp://192.282.34.337/

答案 20 :(得分:0)

/^((([a-zA-Z]{1,2})|([0-9]{1,2})|([a-zA-Z0-9]{1,2})|([a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]))\.)+[a-zA-Z]{2,6}$/
  • ([a-zA-Z]{1,2}) - &gt;仅接受两个字符。

  • ([0-9]{1,2}) - &GT;仅接受两个号码

如果超过两个([a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]),这个正则表达式将处理这个问题。

如果我们想要进行匹配至少一次+将被使用。

答案 21 :(得分:0)

对于 Javascript,您可以查看验证器库: https://www.npmjs.com/package/validator

方法:isFQDN(str [, options])