我正在尝试编写一个全面的正则表达式来验证电话号码。理想情况下,它将处理国际格式,但必须处理美国格式,包括以下格式:
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
1-234-567-8901 x1234
1-234-567-8901 ext1234
1 (234) 567-8901
1.234.567.8901
1/234/567/8901
12345678901
我会回答我的当前尝试,但我希望有人能提供更好和/或更优雅的解决方案。
+44 (0) ...
书写号码,当被要求使用国际前缀时(在这种情况下,您应该完全舍弃 (0)
)。 12345678901
12345678901x1234
345678901x1234
12344678901
12345678901
12345678901
12345678901
+4112345678
+441234567890
在显示时,您可以随意重新格式化。例如:
1 (234) 567-8901
1 (234) 567-8901 x1234
.*
如果用户想要给你他们的电话号码,那就相信他们能填写正确。如果他们不想给你电话号码,那么强制他们输入有效的电话号码将会把他们送到竞争对手的网站或让他们输入一个符合你的正则表达式的随机字符串。我甚至可能会去搜索高收费占星热线的电话号码,然后输入那个号码。"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"
原来在北美地区,这个问题有一个规范,叫做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+))?$
/(?:(?:\+?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})/
。 - Brian Armstrong(?:(?:(\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})
- Brooke.我建议您也可以看一下谷歌的"libphonenumber"库。虽然它不是正则表达式,但它确实可以实现您想要的功能。
例如,它会识别:
15555555555
是一个可能的号码但不是有效的号码,也支持美国以外的国家。
功能亮点:
getNumberType
- 基于号码本身获取号码类型;能够区分固定电话、移动电话、免费电话、高级电话、共享成本、网络电话和个人号码(可行时)。isNumberMatch
- 获取两个号码是否可能相同的置信度。getExampleNumber
/getExampleNumberByType
- 为所有国家/地区提供有效的示例号码,并可指定需要哪种类型的示例电话号码。isPossibleNumber
- 仅使用长度信息快速猜测号码是否是可能的电话号码,比完整验证更快。isValidNumber
- 使用长度和前缀信息对区域内的电话号码进行完整验证。AsYouTypeFormatter
- 用户输入每个数字时即时格式化电话号码。findNumbers
- 在文本输入中查找号码。PhoneNumberOfflineGeocoder
- 提供与电话号码相关的地理信息。电话号码验证的最大问题是它非常依赖于文化背景。
(408) 974–2042
是一个有效的美国号码(999) 974–2042
不是一个有效的美国号码0404 999 999
是一个有效的澳大利亚号码(02) 9999 9999
也是一个有效的澳大利亚号码(09) 9999 9999
不是一个有效的澳大利亚号码正则表达式可用于检查电话号码的格式,但不能真正检查电话号码的有效性。
我建议跳过简单的正则表达式来测试您的电话号码,并使用像Google的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
,不仅可以判断电话号码是否有效(它是有效的),而且您还可以以本地格式获得一致的电话号码格式。
作为额外的奖励,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电话号码数据集实现:
除非你确定只处理来自某个特定地区的电话号码,并且它们都是同一种格式,否则我强烈建议不要自己编写代码验证和显示电话号码,而是使用libphonenumber库。
07700000000
,会出现 Missing or invalid default region.
错误。但是如果我指定国家代码,它就可以通过。 - BugHunterUK/^(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d*)\)?)[\-\.\ \\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\/]?)+)(?:[\-\.\ \\\/]?(?:#|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
- +1 282 282 2828
关于$n,它会保存以下内容:
您可以在https://regex101.com/r/kFzb1s/42上进行测试。
^
和$
时,它会验证“[111] [111] [1111]”? - Ismael Miguel?
。 - Ismael Miguel+1
。问题在于我假设指示符是 1 到 9,然后是 1 个或多个数字,但美国使用 +1
,这破坏了“1个或多个数字”。现在对于这些人来说它可以工作了。 - Ismael Miguel虽然删除所有空白的答案很简洁,但并没有真正解决问题,问题是要找到一个正则表达式。例如,我的测试脚本会下载网页并使用正则表达式提取所有电话号码。既然您仍需要一个正则表达式,那么最好让它做所有的工作。我想到了这个:
1?\W*([2-9][0-8][0-9])\W*([2-9][0-9]{2})\W*([0-9]{4})(\se?x?t?(\d*))?
#!/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*))?';
(4570457-6789
这种常见的打字错误。匹配组也会被扭曲:http://rubular.com/r/TaTP0mHL5c - SooDesuNe(^|[^\d\n])
添加到前面可以避免一般问题,确保它不是紧接着数字。 - btown我之前在另一个SO问题中回答了这个问题,后来决定将我的答案也作为这个帖子的答案,因为没有人在处理如何要求/不要求项目,只是分发正则表达式:
正则表达式错误,匹配到意外的内容根据我在该网站上的帖子,我创建了一个快速指南,以帮助任何人制作自己所需的电话号码格式的正则表达式。我必须说明(就像我在另一个网站上做的那样),如果您限制过多,可能无法获得所需的结果,并且接受世界上所有可能的电话号码的“一刀切”解决方案并不存在 - 只有您决定接受哪种格式。风险自负。
/^
[\s]
或\s
[(]
和[)]
。使用\(
和\)
很丑,会使事情变得混乱。?
-
或[-]
。但是,如果它不是在一系列其他字符的开头或结尾,您可能需要对其进行转义:\-
[-.\s]
将需要连字符、句点或空格。最后一个括号后面的问号将使所有这些都变为该插槽的可选项。\d{3}
:需要一个三位数:000-999。简写为[0-9][0-9][0-9]
。[2-9]
:该位必须填入2到9之间的数字。(\+|1\s)?
:接受一个“加号”或者一个1和一个空格(管道符号“|”表示“或”),并将其设为可选。 "加号"符号必须进行转义。[246]
需要2、4或6。(?:77|78)
或 [77|78]
需要 77 或 78。$/
:结束表达式。[2-9]
块。这意味着你的最小值是2,最大值是9。请相应地进行调整。 - vapcguy我写了最简单的(虽然我不需要其中的点)。
^([0-9\(\)\/\+ \-]*)$
正如下面所提到的,它仅检查字符,而不是其结构/顺序。
()
字符对于一种常见的英国电话号码写法无效:+44 (0) 1234 567890
这表示要么拨打国际号码:+441234567890
01234567890
。如果您只想验证字段中没有随机垃圾(例如来自表单垃圾邮件发送者),则此正则表达式应该很好地完成:
^[0-9+\(\)#\.\s\/ext-]+$
True
,但你真正想要的只是一个正确的电话号码。对于任何试图清理网页或手机应用程序中最终用户输入的电话号码的人,我建议只需编写4或5行代码,逐个字符从左到右进行处理并且删除所有非数字字符。(303)873-9919
变成了3038739919
。删除所有非数字字符后,您可以在正确的位置插入(点.
),插入(连字符-
)或斜杠。 - Samuel Muldoon