跳到主内容
d.devtul.fun
EN
正则 · 域名

域名正则

一个能直接用的域名正则,逐段讲清标签规则,以及正则到底能声称什么、不能声称什么。

正则模式

^(?![0-9]+$)(?!-)[A-Za-z0-9-]{1,63}(?<!-)(\.(?!-)[A-Za-z0-9-]{1,63}(?<!-))*$

匹配一串点分隔的标签,每段一到 63 字符、不以连字符开头或结尾,整串最长 253 字符。

在线测试这个正则

在下面直接改文本 —— 匹配在本机完成,不会上传任何内容。

其它写法

简单点分隔主机
^[A-Za-z0-9.-]+$

读着轻松、能挡空格,但放行了开头或结尾的连字符,也放行连续点。

带字母顶级域
^(?![0-9]+$)(?!-)[A-Za-z0-9-]{1,63}(?<!-)(\.(?!-)[A-Za-z0-9-]{1,63}(?<!-))*\.[A-Za-z]{2,}$

强制末尾是字母顶级域。按设计拒绝 IDN 和 IP 字面量主机。

日常用的域名正则

域名是一串用点连起来的标签。每个标签的规则比大家想的更严,下面这条正则把它编码了进去。在拿用户敲的主机名去做任何危险操作之前,先用它做个健康检查。

^(?![0-9]+$)(?!-)[A-Za-z0-9-]{1,63}(?<!-)(\.(?!-)[A-Za-z0-9-]{1,63}(?<!-))*$

它比那些"简单"版本长是有道理的:便宜版本放过的,恰恰就是会让解析器崩掉的字符串。

标签规则,逐条看

DNS 对每个标签和整串名字都有约束。下面是这条正则强制的东西:

  • 每个标签是 [A-Za-z0-9-]{1,63}:字母、数字、连字符,一到 63 字符。
  • 标签开头的 (?!-) 禁止前导连字符,标签不能以 - 起头。
  • 标签结尾的 (?<!-) 禁止尾随连字符,标签不能以 - 收尾。
  • 第一个标签上的 (?![0-9]+$) 拒绝纯数字名字,那种会和 IP 地址撞车。
  • 整串名字必须不超过 253 字符——这件事你还是得在代码里查,别全丢给正则。

合起来,它们拒绝 -example.com、bad..name.com 和 64 字符的标签,同时接受 sub.example.co.uk。

国际化域名得先转 punycode

用户可能敲 例子.测试 或 münchen.de。这些都是合法域名,但得先转成 punycode:xn--fsqu00a.xn--g6w251d 和 xn--mnchen-3ya.de。一条纯 ASCII 正则会把原样输入拒掉。正确管线是:发现非 ASCII,用平台的 punycode 编码器转(比如 Python 的 idna.encode),再去校验 ASCII 形式。别试图把 UTF-8 塞进正则,编码器已经解决过的边缘情况你会漏。

正则是永远证明不了的事

核心论点:正则可以确认这串东西"长得像域名"。它确认不了这个域名有没有注册、能不能解析、是不是你的。 this-domain-does-not-exist-anywhere.example 完美匹配正则,却解析不到任何东西。所以一条通过的正则只是必要,却一点也算不上"存在"的证明。当存在性真要紧时,配一次 DNS 查询(getaddrinfo、一次 SOA 查询,或查注册商)。

合法与非法,一眼对照

输入期望原因
example.com接受经典两段名
sub.example.co.uk接受多段完全没问题
-example.com拒绝标签以连字符开头
bad..name.com拒绝点之间是个空标签
一长串超过 63 的标签超长则拒绝标签长度上限

把真域名写残的常见错误

错误后果改法
放行下划线SRV 记录才用,主机名不该有除非你真指 SRV,否则别放 _
放行连续点a..b 不是合法名字每个点之间都得有标签
忽略末尾点example.com. 表示根域,是合法的可有可无地放一个结尾点
写死顶级域白名单新顶级域不断冲破你的列表校验长度和形状,别校验成员资格

强制顶级域的更严版本

如果你只在乎经典公网域名、想一上来就拒掉 IP 字面量和 IDN,就强制末尾是字母标签:

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

这更严,也拒绝更多合法输入,所以只在你的下游系统真的吃不进别的任何东西时才用。

正则之外:验证存在性

当域名真得能用时,跨过正则这一步:

  • 校验前先把 IDN 转成 punycode。
  • 跑一次 DNS 解析或 SOA 查询,确认已注册。
  • 注册场景就往那个域名的邮箱发验证链接。
  • 总长度 253 在代码里强制,正则的长度算术太难看。

正则是门房,DNS 是保安。各有各的活,而且只有其中一个知道里面到底是谁。

怎么测你的域名正则

把表中的样例丢给你的正则,再加一个 253 字符的名字和一个 punycode 名字。如果你的正则会放过 a..b 或以连字符开头的标签,就把锚收紧。如果它拒绝了 example.com. 而你需要根域支持,就放行最后的那个点。记住:匹配不等于拥有。

子域、层数,与 253 上限

真实的名字可以很长、嵌套很深。一条只查每段的正则会漏掉整串 253 字符的上限,也漏掉多数解析器实际能处理的层数。 a.b.c.d.e.f.g.h.example.com 形状上合法,但可能超标,也可能撞上解析器的实际上限。正则放行后,在代码里强制 253 字符总长,并想清楚你接不接任意层数。注册表单里限制一下子域层级是合情合理的;DNS 工具就放开语法允许的范围,把最终裁判权交给查询——由它来定这个名字到底活不活。

常见问题

一条好的域名正则长啥样?

强制标签长度 1-63、每段不以连字符开头或结尾、总长 253 字符。但它依然证明不了一个域名存在。

为什么我的域名正则拒绝 IDN?

纯 ASCII 正则会拒绝 Unicode。先把名字转成 punycode,再去校验 ASCII 形式。

顶级域要写白名单吗?

不要。顶级域列表一直在变;校验形状和长度,而不是成员资格。

匹配上的域名就等于真存在吗?

不等于。正则只查格式。要紧的时候用 DNS 查询确认存在性。

其它正则速查

打开完整的正则测试器