常用正则内含 1 场可玩狩猎

电话号码正则:美国格式、E.164,以及何时该停手

同一个电话号码,人们能输入出十几种写法。本文介绍如何匹配带短横线、点、空格、括号和可选 +1 的美国号码,如何检查国际 E.164 格式,以及为什么真正的校验需要借助库。

Regex Hunter 标志

· 阅读约 5 分钟 · 更新于

/^\d{3}[-. ]?\d{3}[-. ]?\d{4}$/

抓住

  • 555-123-4567
  • 555.123.4567
  • 5551234567

放过

  • 555-1234
  • 55-123-4567
  • 555-123-456

找十个人要电话号码,你会收到十种写法:555-123-4567、(555) 123-4567、555.123.4567、+1 555 123 4567、5551234567。它们其实是同一个号码。

电话号码正则既要接受人们真正会输入的写法,又要拦住明显的错误。本文先一步步搭建一个美国号码的正则,再介绍国际格式,最后讲讲正则做不到的部分。每个示例都可以交互,修改正则就能看到各行的变化。

快速答案JavaScript
/^(\+?1[-. ]?)?(\(\d{3}\) ?|\d{3}[-. ]?)\d{3}[-. ]?\d{4}$/

10 位美国电话号码,可带短横线、点或空格,区号用括号括起,前面可加 +1。

匹配

  • 555-123-4567
  • (555) 123-4567
  • +1 555.123.4567

不匹配

  • 555-1234
  • 55-123-4567
  • 555-123-45678

01从数字开始

美国号码由 3 位区号、3 位交换码和 4 位线路号组成。最严格的版本只接受一种格式:

匹配4/4 符合预期
/^\d{3}-\d{3}-\d{4}$/

应当匹配1/1

  • 555-123-4567

不应匹配3/3

  • 555.123.4567
  • 555 123 4567
  • 555-1234
在沙盒里试试
只有短横线写法能通过。点号和空格写法是同一个号码,却被拒绝了。

如果输入格式由你的输入掩码控制,这样没问题。如果用户随意输入,它就太严格了。

02允许常见的分隔符

把每个短横线换成 [-. ]?:短横线、点或空格,? 让它变成可选,这样纯数字也能通过。

匹配7/7 符合预期
/^\d{3}[-. ]?\d{3}[-. ]?\d{4}$/

应当匹配4/4

  • 555-123-4567
  • 555.123.4567
  • 555 123 4567
  • 5551234567

不应匹配3/3

  • 555-1234
  • 55-123-4567
  • 555-123-456
在沙盒里试试
短横线、点、空格,或者什么都不加。数字位数仍必须恰好是 3、3、4。

有个副作用:每个分隔符是各自独立选择的,所以 555-123.4567 也能通过。这通常无伤大雅。如果你希望两个分隔符一致,可以捕获第一个,再用反向引用重复它(详见我们的反向引用指南):

匹配4/4 符合预期
/^\d{3}([-. ]?)\d{3}\1\d{4}$/

应当匹配2/2

  • 555-123-4567
  • 5551234567

不应匹配2/2

  • 555-123.4567
  • 555 123-4567
在沙盒里试试
([-. ]?) 捕获实际用到的分隔符,哪怕是空的,\1 则要求再次出现同一个。

03区号外面的括号

对付 (555) 123-4567,最诱人的办法是用 \(? 和 \)? 让每个括号都变成可选。但这样会接受不配对的输入:

匹配3/3 符合预期
/^\(?\d{3}\)?[-. ]?\d{3}[-. ]?\d{4}$/
  • (555) 123-4567
  • (555-123-4567
  • 555) 123-4567
在沙盒里试试
两个括号各自可选,所以单独一个 ( 或 ) 也能混过去。

用分支就能解决。区号要么在括号里(后面可以跟一个空格),要么不带括号(后面可以跟一个分隔符):

匹配6/6 符合预期
/^(\(\d{3}\) ?|\d{3}[-. ]?)\d{3}[-. ]?\d{4}$/

应当匹配4/4

  • (555) 123-4567
  • (555)123-4567
  • 555-123-4567
  • 555.123.4567

不应匹配2/2

  • (555-123-4567
  • 555) 123-4567
在沙盒里试试
区号有两个分支。只有 ( 而没有 ) 的写法,哪个分支都匹配不上。

04可选的 +1

美国的国家代码是 1,可以写作 +1、1,也可以完全省略。在开头用一个可选分组把它包起来:

匹配7/7 符合预期
/^(\+?1[-. ]?)?(\(\d{3}\) ?|\d{3}[-. ]?)\d{3}[-. ]?\d{4}$/

应当匹配5/5

  • +1 555 123 4567
  • 1-555-123-4567
  • +1 (555) 123-4567
  • 15551234567
  • 555-123-4567

不应匹配2/2

  • +44 20 7946 0958
  • 555-1234
在沙盒里试试
(\+?1[-. ]?)? 是一个可选的加号、一个 1 和一个可选的分隔符。整个分组都可以省略。

对于只面向美国的表单,这已经是一个可靠的正则了。

05用区号规则收紧

真实的美国区号和交换码(中间三位)从不以 0 或 1 开头。在这两处把 \d{3} 换成 [2-9]\d{2},就能拒绝那个经典的假号码:

匹配5/5 符合预期
/^[2-9]\d{2}[-. ]?[2-9]\d{2}[-. ]?\d{4}$/

应当匹配2/2

  • 212-555-0199
  • 415.555.2671

不应匹配3/3

  • 123-456-7890
  • 555-012-3456
  • 555-123-4567
在沙盒里试试
123-456-7890 被排除,因为它的区号以 1 开头。最后两个的交换码分别以 0 和 1 开头,其中就包括我们一直在用的那个示例。

值不值得这么做,取决于你的用户。它能拦住一些输入错误,也会让正则更难读。

06国际号码:E.164

在美国以外,格式差异太大,一个正则根本覆盖不了。与其硬试,大多数系统会用国际标准 E.164 来存储号码:一个 +、国家代码,然后是号码本身,不带空格和标点,最多 15 位数字。国家代码从不以 0 开头。

匹配7/7 符合预期
/^\+[1-9]\d{1,14}$/

应当匹配3/3

  • +15551234567
  • +442079460958
  • +8613800138000

不应匹配4/4

  • 5551234567
  • +1 555 123 4567
  • +0123456789
  • +1234567890123456
在沙盒里试试
一个加号、一个非零的首位数字,然后最多再跟 14 位数字。不允许空格、短横线或括号。

通常的做法是让用户随意输入号码,去掉标点,再检查结果。正则非常适合做去标点这一步:

正则8 字符
/[\s().-]/
在沙盒里试试
任意空格、括号、点或短横线。把每个匹配都替换为空,就能把“+1 (555) 123-4567”变成“+15551234567”。

在 Python 中是 re.sub(r"[\s().-]", "", number),在 JavaScript 中是 number.replace(/[\s().-]/g, "")。

07正则无法告诉你的事

^\+[1-9]\d{1,14}$ 检查的是形状。它无法告诉你:

  • 国家代码是否存在(+999 就不是,而这个正则照样接受),
  • 号码长度对该国家是否正确(英国号码和德国号码长度不同,有些国家的号码长度还不统一),
  • 号码是手机、固话还是尚未分配,
  • 有没有人接听。

要做真正的校验,请使用 Google 的电话号码库 libphonenumber。它了解每个国家的编号方案,并且有大多数语言的移植版本:Python 中的 phonenumbers,JavaScript 中的 libphonenumber-js。它还能把号码格式化用于显示,或转换成 E.164 用于存储:

import phonenumbers

n = phonenumbers.parse("(212) 555-0199", "US")
phonenumbers.format_number(n, phonenumbers.PhoneNumberFormat.E164)  # '+12125550199'
phonenumbers.is_possible_number(n)  # True: the length fits the US plan

和电子邮件地址一样,要证明一个号码能用,唯一的办法就是给它发一个验证码。

08试一试

这里是一个混合了各种格式电话号码的棋盘。你不需要逐一检查每种格式。每个怪物都有连续的十位数字(忽略标点),而无辜者都没有:

可玩狩猎标准杆 11

抓住完整的美国电话号码,放过较短的。

目标 · 抓住 0/5

  • 555-123-4567目标
  • (555) 123-4567目标
  • 555.123.4567目标
  • 5551234567目标
  • +1 555 123 4567目标

无辜词 · 误抓 0

  • 555-1234无辜
  • 12345-6789无辜
  • 2026-10-12无辜
  • 555-123-456无辜
  • 911无辜

输入正则——棋盘会实时更新。

在沙盒里试试
喜欢吗?每天都有新的狩猎。玩今天的狩猎

09检查清单

  • 只接受美国号码时,^(\+?1[-. ]?)?(\(\d{3}\) ?|\d{3}[-. ]?)\d{3}[-. ]?\d{4}$ 能覆盖常见格式。
  • 用分支,而不是两个各自可选的括号,这样 ( 和 ) 才会成对出现。
  • 对于国际号码,用 [\s().-] 去掉标点,并以 E.164 存储。
  • 用 ^\+[1-9]\d{1,14}$ 检查形状,在要紧的场合使用 libphonenumber。
  • 如果需要确认号码真实存在,就发一个验证码。

10继续练习