我正在尝试整合一个全面的正则表达式来验证电话号码.理想情况下它会处理国际格式,但它必须处理美国格式,包括以下内容:
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
我将回答我目前的尝试,但我希望有人能有更好的和/或更优雅的东西.
更好的选择......只需在输入上删除所有非数字字符(除了'x'和前导'+'符号),因为英国倾向于在被+44 (0) ...
要求使用国际前缀时以非标准形式写数字(在这种特殊情况下,你应该(0)
完全抛弃).
然后,您最终得到如下值:
12345678901 12345678901x1234 345678901x1234 12344678901 12345678901 12345678901 12345678901 +4112345678 +441234567890
然后当您显示时,重新格式化您的心灵内容.例如
1 (234) 567-8901 1 (234) 567-8901 x1234
事实证明,至少在北美,有一种称为NANP的规范.
您需要准确指定所需内容.什么是合法分隔符?空格,破折号和句号?不允许分隔符?可以混合分隔符(例如,+ 0.111-222.3333)吗?如何处理扩展(例如,111-222-3333 x 44444)?特殊号码怎么样,比如911?区号是可选的还是必需的?
这是一个7位或10位数的正则表达式,允许扩展,分隔符是空格,短划线或句点:
^(?:(?:\+?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+))?$
.*
如果用户想要给你他的电话号码,那么请相信他是正确的.如果他不想给你,然后强迫他输入一个有效的号码将把他送到竞争对手的网站或让他输入一个适合你的正则表达式的随机字符串.我甚至可能想要查看优质性别性别的数量,然后输入.
我还会将以下任何内容视为网站上的有效条目:
"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"
我还建议查看" libphonenumber "Google图书馆.我知道它不是正则表达式,但它完全符合您的要求.
例如,它将认识到:
15555555555
是可能的数字,但不是有效数字.它还支持美国以外的国家.
功能亮点:
解析/格式化/验证世界上所有国家/地区的电话号码.
getNumberType
- 根据数字本身获取数字的类型; 能够区分固定线路,移动,免费,高级费率,共享成本,VoIP和个人号码(只要可行).
isNumberMatch
- 获得两个数字是否相同的置信度.
getExampleNumber
/ getExampleNumberByType
- 为所有国家/地区提供有效的示例号码,并可选择指定需要哪种类型的示例电话号码.
isPossibleNumber
- 通过仅使用长度信息快速猜测数字是否是可能的语音,比完整验证快得多.
isValidNumber
- 使用长度和前缀信息完全验证区域的电话号码.
AsYouTypeFormatter
- 当用户输入每个数字时,即时格式化电话号码.
findNumbers
- 在文本输入中查找数字.
PhoneNumberOfflineGeocoder
- 提供与电话号码相关的地理信息.
例子
电话号码验证的最大问题是它在文化上非常依赖.
美国
(408) 974–2042
是有效的美国号码
(999) 974–2042
是不是有效的美国号码
澳大利亚
0404 999 999
是有效的澳大利亚号码
(02) 9999 9999
也是一个有效的澳大利亚号码
(09) 9999 9999
是不是有效的澳大利亚号码
正则表达式适用于检查电话号码的格式,但它实际上无法检查电话号码的有效性.
我建议跳过一个简单的正则表达式来测试你的电话号码,并使用像谷歌这样的库libphonenumber
(链接到GitHub项目).
使用一个更复杂的示例,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/twcclegg/libphonenumber-csharp
Objective-C:https://github.com/iziz/libPhoneNumber-iOS
JavaScript:https://github.com/ruimarinho/google-libphonenumber
Elixir:https://github.com/socialpaymentsbv/ex_phone_number
除非你确定你总是要接受来自一个语言环境的数字,并且它们总是采用一种格式,否则我会建议不要为此编写自己的代码,并使用libphonenumber来验证和显示电话号码.
/^(?:(?:\(?(?: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上,它可以节省:
国家指标
电话号码
延期
您可以在https://www.regexpal.com/?fam=99127上进行测试
虽然剥离所有空格的答案很简洁,但它并没有真正解决所提出的问题,即找到一个正则表达式.以我的测试脚本为例,下载网页并使用正则表达式提取所有电话号码.既然你还需要一个正则表达式,你也可以让正则表达式完成所有的工作.我想出了这个:
1?\W*([2-9][0-8][0-9])\W*([2-9][0-9]{2})\W*([0-9]{4})(\se?x?t?(\d*))?
这是一个测试它的perl脚本.匹配时,$ 1包含区号,$ 2和$ 3包含电话号码,$ 5包含扩展名.我的测试脚本从互联网上下载文件并打印其中的所有电话号码.
#!/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"; } }
编辑:
您可以在正则表达式中将\ W*更改为\ s*\W?\ s*以将其收紧一点.在编写表单时,我没有考虑正则表达式,例如,验证表单上的用户输入,但是这种更改使得为此目的使用正则表达式成为可能.
'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*))?';
我在另一个SO问题上回答了这个问题,然后决定将我的答案作为答案包含在这个帖子中,因为没有人在解决如何要求/不需要项目,只是分发正则表达式:正则 表达式工作错误,匹配意外事物
从我在该网站上发布的帖子中,我创建了一个快速指南,帮助任何人为自己想要的电话号码格式制作自己的正则表达式,我会告诫(就像我在其他网站上做的那样)如果你的限制太多,您可能无法获得理想的结果,并且没有"一刀切"的解决方案来接受世界上所有可能的电话号码 - 只有您决定接受的选择格式.使用风险由您自己承担.
开始表达式: /^
如果您想要一个空格,请使用: [\s]
或\s
如果要要求括号,请使用: [(]
和[)]
.使用\(
和\)
丑陋,可以使事情混乱.
如果你想要任何东西是可选的,?
那就把它放在后面
如果你想要一个连字符,只需键入-
或[-]
.但是,如果你不把它放在一系列其他角色的第一个或最后一个,你可能需要逃避它: \-
如果要在插槽中接受不同的选项,请在选项周围添加括号:[-.\s]
将需要连字符,句点或空格.最后一个括号后面的问号将使该插槽的所有选项都成为可选项.
\d{3}
:需要一个3位数字:000-999.简写
[0-9][0-9][0-9]
.
[2-9]
:要求该插槽的数字2-9.
(\+|1\s)?
:接受"加号"或1和空格(管道符号|
,是"或"),并使其成为可选项.必须转义"加号"标志.
如果您希望特定数字与插槽匹配,请输入:[246]
需要2,4或6. [77|78]
将需要77或78.
$/
:结束表达
我写的最简单(虽然我不需要点).
^([0-9\(\)\/\+ \-]*)$
如下所述,它仅检查字符,而不检查其结构/顺序
请注意,剥离()
字符不适用于编写常用的英国号码的样式:+44 (0) 1234 567890
这意味着拨打国际号码:
+441234567890
或拨打英国拨号01234567890
如果你只想验证你在该字段中没有随机垃圾(即来自表单垃圾邮件发送者),这个正则表达式应该做得很好:
^[0-9+\(\)#\.\s\/ext-]+$
请注意,它没有任何特殊规则来确定有多少位数,或者哪些数字在这些数字中有效,它只是验证只有数字,括号,破折号,加号,空格,磅,星号,句号,逗号或字母e
,x
,t
都存在.
它应该与国际号码和本地化格式兼容.您是否预见到某些地区需要允许方形,卷曲或有角度的括号?(目前不包括在内).
如果你想保持每位数的规则(例如美国区号和前缀(交换代码)必须在200-999范围内),祝你好运.保持一个复杂的规则集,在世界上任何一个国家的任何一点都可能过时,听起来并不好玩.
虽然剥离所有/大多数非数字字符可能在服务器端运行良好(特别是如果您计划将这些值传递给拨号器),您可能不希望在验证期间抖动用户的输入,特别是如果您希望它们在另一个领域进行更正.
你看过RegExLib了吗?
输入美国电话号码带来了很多可能性.
我尝试不受限制的正则表达式:
/^[+#*\(\)\[\]]*([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
由您来清理它以进行显示.验证后,它可能是一个数字.
我发现这很好用:
^\(*\+*[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
确保使用全局AND多行标记来确保.
链接:http: //www.regexr.com/3bp4b
如果您正在谈论表单验证,由于国家和提供商的标准不同,用于验证正确含义以及正确数据的正则表达式将非常复杂.它也很难保持最新.
我将这个问题解释为寻找广泛有效的模式,这种模式可能不是内部一致的 - 例如,有一组有效的数字,但没有验证中继线,交换等到国家代码前缀的有效模式.
北美很简单,对于国际而言,我更喜欢使用"惯用"模式,该模式涵盖了人们指定和记住数字的方式:
^((((\(\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
这可能有偏见,因为我的经验仅限于北美,欧洲和亚洲的一小部分.
我对这个主题的回复量增强了我的直觉 - 这个问题几乎有无数的解决方案,其中没有一个会变得优雅.
老实说,我建议你不要试图验证电话号码.即使你可以写一个大,毛茸茸的验证,将允许所有不同的合法形式,这将最终使相当多的东西,甚至远程类似摆在首位的电话号码.
在我看来,最优雅的解决方案是验证最小长度,仅此而已.
这是菲律宾手机号码的简单正则表达式模式:
((\+[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
第一个将匹配任何两位数国家代码,而第二个将匹配菲律宾国家代码.
在这里测试一下:http://refiddle.com/1ox
这是一个与我需要实现的验证最匹配的精彩模式.我不是原作者,但我认为这很值得分享,因为我发现这个问题非常复杂,没有简洁或广泛有用的答案.
以下正则表达式将捕获各种全球电话号码格式中广泛使用的数字和字符组合:
/^\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
你会很难用单一/简单的正则表达式来处理国际号码,请看这篇关于国际(甚至北美)电话号码困难的帖子.
您需要解析前几个数字以确定国家/地区代码是什么,然后根据国家/地区采取不同的行动.
除此之外 - 您提供的列表不包括另一种常见的美国格式 - 从最初的1开始.美国的大多数手机都不需要它,除非他们拨打国际电话,否则它将开始困扰年轻一代.
你已经正确地发现这是一个棘手的问题......
-亚当
到目前为止,这是我最好的尝试.它处理上面的格式,但我确定我缺少一些其他可能的格式.
^\d?(?:(?:[\+]?(?:[\d]{1,3}(?:[ ]+|[\-.])))?[(]?(?:[\d]{3})[\-/)]?(?:[ ]+)?)?(?:[a-zA-Z2-9][a-zA-Z0-9 \-.]{6,})(?:(?:[ ]+|[xX]|(i:ext[\.]?)){1,2}(?:[\d]{1,5}))?$
阅读完这些答案之后,看起来似乎没有一个简单的正则表达式可以解析一堆文本并以任何格式提取电话号码(包括带加号和不带加号的国际电话号码).
这是我最近用于客户项目的内容,我们必须将所有格式的电话号码转换为tel:links.
到目前为止,它一直在处理他们所做的一切,但如果出现错误,我会更新这个答案.
正则表达式:
/(\+*\d{1,})*([ |\(])*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4})/
PHP函数用tel:links替换所有电话号码(万一有人好奇):
function phoneToTel($number) { $return = preg_replace('/(\+*\d{1,})*([ |\(])*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4})/', '$1 ($3) $4-$5', $number); // includes international return $return; }
我相信Number :: Phone :: US和Regexp :: Common (特别是Regexp :: Common :: URI :: RFC2806的源代码)Perl模块可以提供帮助.
应该更详细地说明问题,以解释验证数字的目的.例如,911在美国是有效数字,但911x不是任何x值.这样,电话公司可以在您完成拨号时进行计算.这个问题有几个变种.但是你的正则表达式不检查区号部分,所以这似乎不是一个问题.
与验证电子邮件地址一样,即使您拥有有效的结果,也无法知道在您尝试之前是否将其分配给某人.
如果您正在尝试验证用户输入,为什么不将结果标准化并完成它?如果用户输入的号码无法识别为有效号码,请将其保存为输入或删除不可用的字符.该编号::电话::正常化的Perl模块可能是灵感的源泉.