哪个正则表达式可以匹配有效的国际电话号码?

179

在尝试拨打电话号码之前,我需要确定该号码是否有效。这通话可以在世界各地进行。

哪种正则表达式可以匹配有效的国际电话号码?


6
虽然你是正确的,正则表达式无法确定这一点,但每个外发尝试都会消耗时间和资源。对数字进行快速的合理性检查可以确保显然虚假的呼叫不会阻塞宝贵的信道。 - Abtin Forouzandeh
3
哈哈,@paxdiablo,我猜1-800-CALL-HELP会通过你的RegExp测试...lol - Buhake Sindi
3
这个问题中不清楚的是,如果从美国或世界上任何一个国家拨打这些号码,它们是否必须有效,因为下面大多数解决方案都没有验证一些有效的号码(例如0030 210 12312312-从任何欧盟国家拨打的有效希腊号码)。 - Xeroxoid
@Xeroxoid,问题中标题和正文都提到了“国际电话号码”。国际电话号码是指带有“+”的号码,需要拨打出口代码。在所有欧盟国家(以及大多数其他国家),“00”确实是出口代码,但这仍然使您提供的示例成为特定地区的号码(尽管在许多特定地区有效),而不是国际号码。 - Jon Hanna
2
@JonHanna 我同意你的观点,但从用户体验的角度来看,如果用户输入一个00XX...X号码,测试是否应该通过呢?有些情况下,用户(比如老年人)甚至不知道“+”是什么,也不知道如何在数字/电话键盘上输入它。此外,我仍然可以争辩说00XXX是一个有效的国际号码(即在用户的上下文中),其中使用了退出代码而不是“+”。 - Xeroxoid
显示剩余2条评论
24个回答

136
\+(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|
2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|
4[987654310]|3[9643210]|2[70]|7|1)\d{1,14}$

这是匹配通用国际电话号码的正确格式。我用标准国际访问代码标识符“+”替换了针对美国固定电话的国际访问代码011,并使其强制使用。我还将国内号码的最小位数更改为至少一位数字。

请注意,如果您以此格式输入号码到您的手机通讯录中,您可以成功地拨打通讯录中的任何号码,无论您在哪里旅行。对于固定电话,请将加号替换为您正在拨打的国家的国际访问代码。

请注意,这不考虑各国家/地区的国家号码计划规则 - 具体来说,它允许在可能不被国家号码计划允许的位置上出现零和一,并且对于某些国家,它允许号码长度超过国家号码计划(例如美国)。


7
我认为这个看起来很合理。我打算使用这个。 - Robert Johnstone
34
这不是有效的。欧洲电话号码在开头可以以双0开始,而不需要加上+号。因此,像+44 8984 1234(英国)这样的电话号码,如果写成0044 8984 1234也是完全有效的。但是,这个正则表达式(以及其他答案)并不支持此格式。 - Xeroxoid
10
结合了@fezfox的改进和长度优化:^\+((?:9[679]|8[035789]|6[789]|5[90]|42|3[578]|2[1-689])|9[0-58]|8[1246]|6[0-6]|5[1-8]|4[013-9]|3[0-469]|2[70]|7|1)(?:\W*\d){0,13}\d$ - SamWhan
5
从用户体验的角度来看,允许在号码前面加上“00”可能是有道理的。但从开发和维护的角度来看,我认为强制所有号码以“+”开头甚至每次获取时用“+”替换“00”都是完全可以接受的 - 特别是考虑到大多数人都知道“+”格式(大多数国际电话输入字段都要求这样)。此外,这是一个一行代码就能解决的问题,而且更易读。这种方法还可以确保所有电话号码都处于相同的格式,并使您的验证更少出错,从而使整个过程更易于维护。 - milosmns
3
@milosmns 是的,强制所有数字以“+”开头是完全可以的,有很多用户体验友好的方法来实现。例如,让他们从下拉菜单中选择自己的国家,并显示你要在电话号码前加上+44(英国的情况)。这样就清楚地表明必须输入以“+”开头的号码。 - Danagon
显示剩余7条评论

73

所有国家代码都由ITU定义。以下正则表达式基于ITU-T E.164和ITU操作公告第930号附录—2009年4月15日。它包含了所有现行国家代码以及未来预留的代码。虽然可以将其缩短一些,但我决定单独包括每个代码。

这是针对从美国起始的电话呼叫。对于其他国家,请用该国的拨号计划中适当的代码替换国际访问代码(正则表达式开头的011)。

此外,请注意ITU E.164定义了完整的国际电话号码的最大长度为15位数字。这意味着三位数字的国家代码会产生多达12位附加数字,而一位数字的国家代码可能包含多达14个附加数字。因此,

[0-9]{0,14}$

在正则表达式的末尾。

最重要的是,这个正则表达式并不意味着号码是有效的 - 每个国家都定义了自己的内部编号计划。这只能确保国家代码是有效的。

^011(999|998|997|996|995|994|993|992|991| 990|979|978|977|976|975|974|973|972|971|970| 969|968|967|966|965|964|963|962|961|960|899| 898|897|896|895|894|893|892|891|890|889|888| 887|886|885|884|883|882|881|880|879|878|877| 876|875|874|873|872|871|870|859|858|857|856| 855|854|853|852|851|850|839|838|837|836|835| 834|833|832|831|830|809|808|807|806|805|804| 803|802|801|800|699|698|697|696|695|694|693| 692|691|690|689|688|687|686|685|684|683|682| 681|680|679|678|677|676|675|674|673|672|671| 670|599|598|597|596|595|594|593|592|591|590| 509|508|507|506|505|504|503|502|501|500|429| 428|427|426|425|424|423|422|421|420|389|388| 387|386|385|384|383|382|381|380|379|378|377| 376|375|374|373|372|371|370|359|358|357|356| 355|354|353|352|351|350|299|298|297|296|295| 294|293|292|291|290|289|288|287|286|285|284| 283|282|281|280|269|268|267|266|265|264|263| 262|261|260|259|258|257|256|255|254|253|252| 251|250|249|248|247|246|245|244|243|242|241| 240|239|238|237|236|235|234|233|232|231|230| 229|228|227|226|225|224|223|222|221|220|219| 218|217|216|215|214|213|212|211|210|98|95|94| 93|92|91|90|86|84|82|81|66|65|64|63|62|61|60| 58|57|56|55|54|53|52|51|49|48|47|46|45|44|43| 41|40|39|36|34|33|32|31|30|27|20|7|1)[0-9]{0, 14}$


17
几乎说得没错... "011" 不是国际码的一部分,只是在美国打国际电话需要拨打的前缀。这个前缀会根据所在地的不同而变化... 所以这个前缀并不是号码的一部分。 - Gabriel Magana
4
@gmagana - 我在我的回答中提到了这一点(第二段)。 - Abtin Forouzandeh
2
我的观点是这不是电话号码的一部分。这就像说美国国家长途拨号前缀“1”是电话号码的一部分一样。 - Gabriel Magana
3
@Roger Pate:我花了一些时间来弄清楚这个问题,希望对其他人有用。我也希望有人能提供更好的解决方案(这就是为什么我没有将自己的答案标记为已接受的原因)。 - Abtin Forouzandeh
2
疯狂的是,对于insanity的评论获得了比回答更多的投票。 - Jimi
显示剩余6条评论

41

这是进一步的优化。

\+(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|
2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|
4[987654310]|3[9643210]|2[70]|7|1)
\W*\d\W*\d\W*\d\W*\d\W*\d\W*\d\W*\d\W*\d\W*(\d{1,2})$

(i) 允许有效的国际前缀
(ii) 后跟9或10位数字,可以使用任何类型或放置分隔符(除了在最后两个数字之间)

这将匹配:

+1-234-567-8901  
+61-234-567-89-01  
+46-234 5678901  
+1 (234) 56 89 901  
+1 (234) 56-89 901  
+46.234.567.8901  
+1/234/567/8901  

我知道这是一个旧答案,但是否有任何选项可以使数字1在美国的数字中变为可选? - Adam Fratino
你想要做的是 (i) 使 "+" 可选,(ii) 国际代码也可选。因此,在 + 和第一个闭括号后面加上 "?"。 - fezfox
@ManosPasgiannis 嗯,是的,正如指定的“后跟9或10个数字”。在塞浦路斯,似乎你使用8,所以只需通过删除一次 \d\W* 实例来调整最后一个序列,并使最后一个表达式为 (\d{1,3})。 - fezfox

32

没有对那些出色答案的批评,我只是想提供我们管理内容创作者使用的简单解决方案:

^(\+|00)[1-9][0-9 \-\(\)\.]{7,32}$

必须以加号或两个零开头,并使用至少一点数字。空格、括号、减号和小数点都是可选的,不允许使用其他字符。

您可以安全地删除所有非数字(除了+号),并将其用于tel:输入中。数字将具有通用的表示形式,我不必担心过于严格。


31
你可以使用来自谷歌的库libphonenumber
PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
String decodedNumber = null;
PhoneNumber number;
    try {
        number = phoneNumberUtil.parse(encodedHeader, null);
        decodedNumber = phoneNumberUtil.format(number, PhoneNumberFormat.E164);
    } catch (NumberParseException e) {
        e.printStackTrace();
    }

3
这可能是一个不错的解决方案,但在使用这个库之前,你需要导入大量的js来检查电话号码,因为libphonenumber.js需要closure library... 这不是一个轻量级的解决方案 :/ - J.BizMai
@J.BizMai 不完全是这样... 闭包库的代码是设计用 Closure Compiler 编译的,它可以进行死代码消除。启用高级优化后,编译后的库可能非常轻巧和高效。 - Pocketsand
感谢您在这里做出的贡献。如果有人感兴趣,我想提一下 Python 端口。如果 @J.BizMai 的评论对您有共鸣,那么它更像是一个“轻量级解决方案”:https://github.com/daviddrysdale/python-phonenumbers - Joel Mellon

28

修改了 @Eric 的正则表达式——增加了一个所有国家代码的列表(从 xxxdepy @ Github 获取)。

/(\+|00)(297|93|244|1264|358|355|376|971|54|374|1684|1268|61|43|994|257|32|229|226|880|359|973|1242|387|590|375|501|1441|591|55|1246|673|975|267|236|1|61|41|56|86|225|237|243|242|682|57|269|238|506|53|5999|61|1345|357|420|49|253|1767|45|1809|1829|1849|213|593|20|291|212|34|372|251|358|679|500|33|298|691|241|44|995|44|233|350|224|590|220|245|240|30|1473|299|502|594|1671|592|852|504|385|509|36|62|44|91|246|353|98|964|354|972|39|1876|44|962|81|76|77|254|996|855|686|1869|82|383|965|856|961|231|218|1758|423|94|266|370|352|371|853|590|212|377|373|261|960|52|692|389|223|356|95|382|976|1670|258|222|1664|596|230|265|60|262|264|687|227|672|234|505|683|31|47|977|674|64|968|92|507|64|51|63|680|675|48|1787|1939|850|351|595|970|689|974|262|40|7|250|966|249|221|65|500|4779|677|232|503|378|252|508|381|211|239|597|421|386|46|268|1721|248|963|1649|235|228|66|992|690|993|670|676|1868|216|90|688|886|255|256|380|598|1|998|3906698|379|1784|58|1284|1340|84|678|681|685|967|27|260|263)(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\d{4,20}$/

1
非常好用,荷兰电话号码也可以。谢谢! - mauvm
1
非常聪明的解决方案!(当然要点赞+1) - Anton Antonov

16
我使用这个:
/([0-9\s\-]{7,})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$/

优点:可以识别以 + 或 011 开头的号码,可以长度任意,而且处理多种扩展约定。(#、x、ext、extension)


这个格式非常接近大多数国际电话号码的格式。 - feeela

13

这将适用于国际号码;

C#:

@"^((\+\d{1,3}(-| )?\(?\d\)?(-| )?\d{1,5})|(\(?\d{2,6}\)?))(-| )?(\d{3,4})(-| )?(\d{4})(( x| ext)\d{1,5}){0,1}$"

JS:

/^((\+\d{1,3}(-| )?\(?\d\)?(-| )?\d{1,5})|(\(?\d{2,6}\)?))(-| )?(\d{3,4})(-| )?(\d{4})(( x| ext)\d{1,5}){0,1}$/

9
这是您的正则表达式的“优化”版本:
^011(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|
2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|
4[987654310]|3[9643210]|2[70]|7|1)\d{0,14}$

您可以将\d替换为[0-9],如果您的正则表达式语法不支持\d

9

对于,我找到了这个有用的内容:

let phoneRegEx = "^((\\+)|(00)|(\\*)|())[0-9]{3,14}((\\#)|())$"

+91 9999999999 失败 - Sahil Mahajan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接