一个全面的电话号码validation正则expression式

我试图把一个综合的正则expression式来validation电话号码。 理想情况下,它将处理国际格式,但它必须处理美国格式,包括以下内容:

  • 1-234-567-8901
  • 1-234-567-8901 x1234
  • 1-234-567-8901 ext1234
  • 1(234)567-8901
  • 1.234.567.8901
  • 1/234/567/8901
  • 12345678901

我会回答我目前的尝试,但我希望有人有更好的和/或更优雅的东西。

更好的select…只是去除input中的所有非数字字符(除了'x'和前面的'+'符号),注意因为英国人倾向于以非标准forms+44 (0) ...写数字+44 (0) ...当被要求使用国际前缀时(在这种情况下,你应该完全抛弃(0) )。

然后,你最终得到的值如下:

  12345678901 12345678901x1234 345678901x1234 12344678901 12345678901 12345678901 12345678901 +4112345678 +441234567890 

然后当你展示,重新格式化你的心中的内容。 例如

  1 (234) 567-8901 1 (234) 567-8901 x1234 

事实certificate,这是一个规范,至less在北美,称为NANP 。

你需要明确指定你想要的。 什么是合法分隔符? 空格,破折号和句点? 没有分隔符允许? 可以混合使用分隔符(例如+ 0.111-222.3333)吗? 扩展(如111-222-3333 x 44444)如何处理? 特殊数字如911? 地区代码是可选的还是必需的?

这里是一个7或10位数字的正则expression式,允许扩展名,分隔符是空格,破折号或句点:

 ^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$ 
 .* 

如果用户想给你他的电话号码,那么请相信他是正确的。 如果他不想给你,然后强迫他input一个有效的数字将会把他送到竞争对手的网站或让他input一个随机的string,适合你的正则expression式。 我甚至可能会试图查找一个保费率性线的数量,然后input。

在网站上,我还会考虑以下任何有效的条目:

 "123 456 7890 until 6pm, then 098 765 4321" "123 456 7890 or try my mobile on 098 765 4321" "ex-directory - mind your own business" 

我也build议看看“ libphonenumber ”谷歌图书馆。 我知道这不是正则expression式,但它确实是你想要的。

例如,它会认识到:

 15555555555 

是可能的数字,但不是有效的数字。 它也支持美国以外的国家。

function亮点:

  • parsing/格式化/validation世界上所有国家/地区的电话号码。
  • getNumberType – 根据数字本身获取数字的types; 能够区分固定电话,移动电话,免费电话,付费电话费用,共享费用,VoIP和个人电话号码(只要可行)。
  • isNumberMatch – 获取两个数字是否相同的置信度。
  • getExampleNumber / getExampleNumberByType – 为所有国家/地区提供有效的示例编号,并指定需要哪种types的示例电话号码。
  • isPossibleNumber – 通过仅使用长度信息快速猜测数字是否是可能的数字,比完整的validation快得多。
  • isValidNumber – 使用长度和前缀信息完整validation某个地区的电话号码。
  • AsYouTypeFormatter – 当用户input每个数字时,即时格式化电话号码。
  • findNumbers – 在文本input中查找数字。
  • PhoneNumberOfflineGeocoder – 提供与电话号码相关的地理信息。

例子

电话号码validation的最大问题在于文化上的依赖性。

  • 美国
    • (408) 974–2042是一个有效的美国号码
    • (999) 974–2042 不是有效的美国号码
  • 澳大利亚
    • 0404 999 999是一个有效的澳大利亚号码
    • (02) 9999 9999也是一个有效的澳大利亚号码
    • (09) 9999 9999 不是澳大利亚的有效号码

正则expression式可以检查电话号码的格式,但是它不能检查电话号码的有效性

我会build议跳过一个简单的正则expression式来testing你的电话号码,并使用一个库,如谷歌的libphonenumber (链接到GitHub项目) 。

介绍libphonenumber!

使用一个更复杂的例子1-234-567-8901 x1234 ,您可以从libphonenumber (链接到在线演示)中获得以下数据 :

 Validation Results Result from isPossibleNumber() true Result from isValidNumber() true Formatting Results: E164 format +12345678901 Original format (234) 567-8901 ext. 123 National format (234) 567-8901 ext. 123 International format +1 234-567-8901 ext. 123 Out-of-country format from US 1 (234) 567-8901 ext. 123 Out-of-country format from CH 00 1 234-567-8901 ext. 123 

因此,您不仅可以了解电话号码是否有效(是),还可以在您的区域设置中获得一致的电话号码格式。

作为奖励, libphonenumber还有许多数据集来检查电话号码的有效性,所以检查一个数字如+61299999999 (国际版(02) 9999 9999 )将返回一个有效的数字格式:

 Validation Results Result from isPossibleNumber() true Result from isValidNumber() true Formatting Results E164 format +61299999999 Original format 61 2 9999 9999 National format (02) 9999 9999 International format +61 2 9999 9999 Out-of-country format from US 011 61 2 9999 9999 Out-of-country format from CH 00 61 2 9999 9999 

libphonenumber还为您提供了许多额外的好处,例如抓取电话号码被检测到的位置,还从电话号码中获取时区信息:

 PhoneNumberOfflineGeocoder Results Location Australia PhoneNumberToTimeZonesMapper Results Time zone(s) [Australia/Sydney] 

但澳大利亚的无效电话号码( (09) 9999 9999 )返回,它不是一个有效的电话号码。

 Validation Results Result from isPossibleNumber() true Result from isValidNumber() false 

Google的版本包含Java和Javascript的代码,但是人们也已经为使用Google i18n电话号码数据集的其他语言实现了库:

  • PHP : https : //github.com/giggsey/libphonenumber-for-php
  • Python : https : //github.com/daviddrysdale/python-phonenumbers
  • Ruby : https : //github.com/sstephenson/global_phone
  • C# : https : //github.com/erezak/libphonenumber-csharp
  • Objective-C : https : //github.com/iziz/libPhoneNumber-iOS

除非你确定你总是接受一个地区的电话号码,而且他们总是采用一种格式,否则我会强烈build议不要为此编写自己的代码,并使用libphonenumber来validation和显示电话号码。

虽然解决所有空白的答案是整齐的,但它并不能真正解决所提出的问题,即find一个正则expression式。 举个例子,我的testing脚本下载一个网页,并使用正则expression式提取所有电话号码。 因为无论如何你需要一个正则expression式,你也可以让正则expression式完成所有的工作。 我想出了这个:

 1?\W*([2-9][0-8][0-9])\W*([2-9][0-9]{2})\W*([0-9]{4})(\se?x?t?(\d*))? 

这是一个perl脚本来testing它。 匹配时,$ 1包含区号,$ 2和$ 3包含电话号码,$ 5包含扩展名。 我的testing脚本从互联网上下载一个文件,并打印所有的电话号码。

 #!/usr/bin/perl my $us_phone_regex = '1?\W*([2-9][0-8][0-9])\W*([2-9][0-9]{2})\W*([0-9]{4})(\se?x?t?(\d*))?'; my @tests = ( "1-234-567-8901", "1-234-567-8901 x1234", "1-234-567-8901 ext1234", "1 (234) 567-8901", "1.234.567.8901", "1/234/567/8901", "12345678901", "not a phone number" ); foreach my $num (@tests) { if( $num =~ m/$us_phone_regex/ ) { print "match [$1-$2-$3]\n" if not defined $4; print "match [$1-$2-$3 $5]\n" if defined $4; } else { print "no match [$num]\n"; } } # # Extract all phone numbers from an arbitrary file. # my $external_filename = 'http://web.textfiles.com/ezines/PHREAKSANDGEEKS/PnG-spring05.txt'; my @external_file = `curl $external_filename`; foreach my $line (@external_file) { if( $line =~ m/$us_phone_regex/ ) { print "match $1 $2 $3\n"; } } 

编辑:

您可以在正则expression式中将\ W *更改为\ s * \ W?\ s *以将其拉紧一点。 我没有考虑用户在input表单时validation用户input的正则expression式,但是这种改变使得使用正则expression式成为可能。

 '1?\s*\W?\s*([2-9][0-8][0-9])\s*\W?\s*([2-9][0-9]{2})\s*\W?\s*([0-9]{4})(\se?x?t?(\d*))?'; 

/^(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(\d+))?$/i

这匹配:

  - (+351) 282 43 50 50 - 90191919908 - 555-8909 - 001 6867684 - 001 6867684x1 - 1 (234) 567-8901 - 1-234-567-8901 x1234 - 1-234-567-8901 ext1234 - 1-234 567.89/01 ext.1234 - 1(234)5678901x1234 - (123)8575973 - (0055)(123)8575973 

在$ n上,它节省了:

  1. 国家指标
  2. 电话号码
  3. 延期

您可以在https://www.regexpal.com/?fam=99127上进行testing

我在另一个SO问题上回答了这个问题,然后决定在我的答案中也包括我的答案,因为没有人解决如何要求/不需要项目,只是发出正则expression式 :正则expression式工作错了,匹配意想不到的东西

从我在该网站上发表的文章中,我已经创build了一个快速指南,帮助任何人为自己想要的电话号码格式制定自己的正则expression式,我会告诉你(如我在另一个网站上做的那样),如果你太严格,你可能得不到预期的结果,并且没有“万能的”解决scheme来接受世界上所有可能的电话号码 – 只有你决定接受的select格式。 使用风险自负。

快速备忘单

  • 开始expression式: /^
  • 如果您想要空间,请使用: [\s]\s
  • 如果您想要括号,请使用: [(][)] 。 使用\(\)是丑陋的,可以使事情混乱。
  • 如果你想要任何东西是可选的,把一个? 之后
  • 如果你想要一个连字符,只需键入-[-] 。 如果你不把它放在一系列其他angular色中,你可能需要将其转义: \-
  • 如果你想接受一个插槽中的不同select,请在选项周围加上括号: [-.\s]将需要连字符,句点或空格。 最后一个括号后的问号将使所有这些可选的插槽。
  • \d{3} :需要一个三位数字:000-999。 速记[0-9][0-9][0-9]
  • [2-9] :需要该插槽的数字2-9。
  • (\+|1\s)? :接受一个“加号”或1和一个空格(pipe道字符, | ,是“或”),并使其成为可选项。 “加号”必须逃脱。
  • 如果你想要特定的数字来匹配一个插槽,请input: [246]将需要2,4或6. [77|78]将需要77或78。
  • $/ :结束expression式

我写了最简单的(虽然我不需要点)。

  ^([0-9 \(\)\ / \ + \  - ] *)$ 

如下所述,它只检查字符,而不检查结构/顺序

请注意,剥离()字符不适用于编写常用英国数字的样式: +44 (0) 1234 567890这意味着拨打国际号码:
+441234567890
或在英国拨打01234567890

如果你只是想validation你没有在该领域的随机垃圾(即从forms垃圾邮件发送者)这个正则expression式应该做的很好:

 ^[0-9+\(\)#\.\s\/ext-]+$ 

请注意,它没有任何特定的规则,有多less数字,或哪些数字在这些数字是有效的,它只是validation只有数字,括号,破折号,加号,空格,英镑,星号,句点,逗号或字母ext存在。

它应该与国际号码和本地化格式兼容。 您是否预见到有些地区需要允许方形,curl或有angular度的支架? (目前他们不包括在内)。

如果你想保持每个数字的规则(如美国地区代码和前缀(交换代码)必须在200-999的范围内),祝你好运。 保持世界上任何国家未来任何时候都可能过时的复杂规则,这听起来并不乐观。

而在服务器端剥离所有/大部分非数字字符可能会工作得很好(特别是如果您计划将这些值传递给拨号程序),您可能不希望在validation过程中使用户的input中断,特别是如果您希望它们在另一个领域纠正。

你有没有看过RegExLib ?

input美国的电话号码带来了相当多的可能性。

我发现这工作得很好:

 ^\(*\+*[1-9]{0,3}\)*-*[1-9]{0,3}[-. /]*\(*[2-9]\d{2}\)*[-. /]*\d{3}[-. /]*\d{4} *e*x*t*\.* *\d{0,4}$ 

它适用于这些数字格式:

 1-234-567-8901 1-234-567-8901 x1234 1-234-567-8901 ext1234 1 (234) 567-8901 1.234.567.8901 1/234/567/8901 12345678901 1-234-567-8901 ext. 1234 (+351) 282 433 5050 

确保使用全局和多行标志来确保。

链接: http : //www.regexr.com/3bp4b

如果你正在谈论表单validation,由于国家和提供商标准的不同,用于validation正确含义和正确数据的正则expression式将非常复杂。 这也很难保持最新。

我把这个问题解释为寻找一个广泛有效的模式,这个模式可能不是内部一致的 – 例如有一组有效的数字,但不能validation中继线,交换等到国家代码前缀的有效模式。

北美是直接的,对于国际,我更喜欢使用“惯用”模式,涵盖人们指定和记住他们的数字的方式:

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

北美模式确保如果括号中包含括号。 国际账户为可选的初始“+”和国家代码。 之后,你就成语了。 有效的匹配是:

  • (xxx)xxx-xxxx
  • (xxx)-xxx-xxxx
  • (xxx)xxx-xxxx x123
  • 12 1234 123 1 x1111
  • 12 12 12 12 12
  • 12 1 1234 123456 x12345
  • +12 1234 1234
  • +12 12 12 1234
  • +12 1234 5678
  • +12 12345678

这可能是有偏见的,因为我的经验仅限于北美,欧洲和一小撮亚洲。

我试图在一个不受限制的正则expression式:

 /^[+#*\(\)\[\]]*([0-9][ ext+-pw#*\(\)\[\]]*){6,45}$/ 

接受:

 +(01) 123 (456) 789 ext555 123456 *44 123-456-789 [321] 123456 123456789012345678901234567890123456789012345 *****++[](][((( 123456tteexxttppww 

拒绝:

 mob 07777 777777 1234 567 890 after 5pm john smith (empty) 1234567890123456789012345678901234567890123456 911 

这是由你来消毒它的显示。 validation后,它可能是一个数字,但。

你将很难用一个/简单的正则expression式处理国际电话号码,看到这个国际(甚至是北美)电话号码的困难。

您需要parsing前几位数字以确定国家代码,然后根据国家采取不同的行动。

除此之外 – 你所提供的名单不包括美国的另一种常见格式 – 离开最初的1.美国的大多数手机不需要它,而且除非他们拨打国际电话,否则它将开始困扰年轻一代。

你已经正确地认定这是个棘手的问题

-亚当

我对这个问题的答复使我的直觉感到强烈 – 对这个问题的解决scheme实际上是无限的,没有哪一个会变得优雅。

老实说,我会build议你不要尝试validation电话号码。 即使你可以写一个大的,多毛的validation器,允许所有不同的合法格式,它最终将允许几乎任何东西,甚至远远类似于一个电话号码。

在我看来,最优雅的解决scheme是validation最小长度,仅此而已。

这是菲律宾手机号码简单的正则expression式模式:

 ((\+[0-9]{2})|0)[.\- ]?9[0-9]{2}[.\- ]?[0-9]{3}[.\- ]?[0-9]{4} 

要么

 ((\+63)|0)[.\- ]?9[0-9]{2}[.\- ]?[0-9]{3}[.\- ]?[0-9]{4} 

将匹配这些:

 +63.917.123.4567 +63-917-123-4567 +63 917 123 4567 +639171234567 09171234567 

第一个将匹配任何两位数的国家代码,而第二个将独家匹配菲律宾国家代码。

在这里testing: http : //refiddle.com/1ox

看完这些答案后,看起来没有一个简单的正则expression式,可以通过一堆文本parsing,并以任何格式(包括国际有和没有加号)拉出电话号码。

以下是我最近用于客户项目的地方,我们必须将所有电话号码以任何格式转换为电话:链接。

到目前为止,它一直在处理所有的事情,但是如果出现错误,我会更新这个答案。

正则expression式:

/(\+*\d{1,})*([ |\(])*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4})/

PHP函数用tel:链接replace所有电话号码(万一有人好奇):

 function phoneToTel($number) { $return = preg_replace('/(\+*\d{1,})*([ |\(])*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4})/', '<a href="tel:$1$3$4$5">$1 ($3) $4-$5</a>', $number); // includes international return $return; } 

这是一个非常好的模式,与我需要实现的validation最为匹配。 我不是原作者,但我认为这是值得分享的,因为我发现这个问题非常复杂,没有一个简洁或广泛有用的答案。

下面的正则expression式将捕捉广泛使用的数字和字符组合在各种全球电话号码格式:

/^\s*(?:\+?(\d{1,3}))?([-. (]*(\d{3})[-. )]*)?((\d{3})[-. ]*(\d{2,4})(?:[-.x ]*(\d+))?)\s*$/gm

正:
+42 555.123.4567
+ 1-(800)-123-4567
+7 555 1234567
+7(926)1234567
(926)1234567
79261234567
926 1234567
9261234567
1234567
123-4567
123-89-01
495 1234567
469 123 45 67
89261234567
8(926)1234567
926.123.4567
415-555-1234
650-555-2345
(416)555-3456
202 555 4567
4035555678
1 416 555 9292

负:
926 3 4
8 800 600-APPLE

原始来源: http : //www.regexr.com/38pvb

这是我迄今为止最好的尝试。 它处理上面的格式,但我相信我错过了一些其他可能的格式。

 ^\d?(?:(?:[\+]?(?:[\d]{1,3}(?:[ ]+|[\-.])))?[(]?(?:[\d]{3})[\-/)]?(?:[ ]+)?)?(?:[a-zA-Z2-9][a-zA-Z0-9 \-.]{6,})(?:(?:[ ]+|[xX]|(i:ext[\.]?)){1,2}(?:[\d]{1,5}))?$ 

我相信Number :: Phone :: US和Regexp :: Common (特别是Regexp :: Common :: URI :: RFC2806的源代码)Perl模块可以提供帮助。

这个问题应该更详细地说明,以解释validation数字的目的。 例如,911在美国是有效的数字,但是911x不是x的任何值。 这样电话公司就可以计算出拨号完成的时间。 这个问题有几个变化。 但是你的正则expression式并不检查区号部分,所以这似乎不是一个问题。

就像validation电子邮件地址一样,即使你有一个有效的结果,你也不知道它是否分配给某个人,直到你尝试。

如果您正在尝试validation用户input,为什么不正常化结果并完成它? 如果用户input号码,则无法识别为有效号码,请将其保存为input号码或删除不可更改的字符。 Number :: Phone :: Normalize Perl模块可能是灵感的来源。

我为一家市场研究公司工作,我们必须全面过滤这些types的投入。 你太复杂了。 只删除非字母数字的字符,看看是否有扩展名。

对于进一步的分析,您可以订阅许多提供商之一,让您访问有效数字的数据库,以及告诉你,如果他们是固定电话或手机,断开连接,等等。

Do a replace on formatting characters, then check the remaining for phone validity. In PHP,

  $replace = array( ' ', '-', '/', '(', ')', ',', '.' ); //etc; as needed preg_match( '/1?[0-9]{10}((ext|x)[0-9]{1,4})?/i', str_replace( $replace, '', $phone_num ); 

Breaking a complex regexp like this can be just as effective, but much more simple.

I found this to be something interesting. I have not tested it but it looks as if it would work

 <?php /* string validate_telephone_number (string $number, array $formats) */ function validate_telephone_number($number, $formats) { $format = trim(ereg_replace("[0-9]", "#", $number)); return (in_array($format, $formats)) ? true : false; } /* Usage Examples */ // List of possible formats: You can add new formats or modify the existing ones $formats = array('###-###-####', '####-###-###', '(###) ###-###', '####-####-####', '##-###-####-####', '####-####', '###-###-###', '#####-###-###', '##########'); $number = '08008-555-555'; if(validate_telephone_number($number, $formats)) { echo $number.' is a valid phone number.'; } echo "<br />"; $number = '123-555-555'; if(validate_telephone_number($number, $formats)) { echo $number.' is a valid phone number.'; } echo "<br />"; $number = '1800-1234-5678'; if(validate_telephone_number($number, $formats)) { echo $number.' is a valid phone number.'; } echo "<br />"; $number = '(800) 555-123'; if(validate_telephone_number($number, $formats)) { echo $number.' is a valid phone number.'; } echo "<br />"; $number = '1234567890'; if(validate_telephone_number($number, $formats)) { echo $number.' is a valid phone number.'; } ?> 

You would probably be better off using a Masked Input for this. That way users can ONLY enter numbers and you can format however you see fit. I'm not sure if this is for a web application, but if it is there is a very click jQuery plugin that offers some options for doing this.

http://digitalbush.com/projects/masked-input-plugin/

They even go over how to mask phone number inputs in their tutorial.

Here's one that works well in JavaScript. It's in a string because that's what the Dojo widget was expecting.

It matches a 10 digit North America NANP number with optional extension. Spaces, dashes and periods are accepted delimiters.

 "^(\\(?\\d\\d\\d\\)?)( |-|\\.)?\\d\\d\\d( |-|\\.)?\\d{4,4}(( |-|\\.)?[ext\\.]+ ?\\d+)?$" 

I was struggling with the same issue, trying to make my application future proof, but these guys got me going in the right direction. I'm not actually checking the number itself to see if it works or not, I'm just trying to make sure that a series of numbers was entered that may or may not have an extension.

Worst case scenario if the user had to pull an unformatted number from the XML file, they would still just type the numbers into the phone's numberpad 012345678x5 , no real reason to keep it pretty. That kind of RegEx would come out something like this for me:

 \d+ ?\w{0,9} ?\d+ 
  • 01234467 extension 123456
  • 01234567x123456
  • 01234567890

My inclination is to agree that stripping non-digits and just accepting what's there is best. Maybe to ensure at least a couple digits are present, although that does prohibit something like an alphabetic phone number "ASK-JAKE" for example.

A couple simple perl expressions might be:

 @f = /(\d+)/g; tr/0-9//dc; 

Use the first one to keep the digit groups together, which may give formatting clues. Use the second one to trivially toss all non-digits.

Is it a worry that there may need to be a pause and then more keys entered? Or something like 555-1212 (wait for the beep) 123?

  pattern="^[\d|\+|\(]+[\)|\d|\s|-]*[\d]$" validateat="onsubmit" 

Must end with a digit, can begin with ( or + or a digit, and may contain + – ( or )

Working example for Turkey, just change the

 d{9} 

according to your needs and start using it.

 function validateMobile($phone) { $pattern = "/^(05)\d{9}$/"; if (!preg_match($pattern, $phone)) { return false; } return true; } $phone = "0532486061"; if(!validateMobile($phone)) { echo 'Incorrect Mobile Number!'; } $phone = "05324860614"; if(validateMobile($phone)) { echo 'Correct Mobile Number!'; }