用于电话号码验证的全面正则表达式
我正在尝试综合使用一个正则表达式来验证电话号码。理想情况下,它将处理国际格式,但必须处理美国格式,包括以下内容:
- 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
我会以目前的尝试回答,但我希望有人能做得更好和/或者更优雅。
解决方案
到目前为止,这是我最好的尝试。它处理上面的格式,但是我确定我缺少其他可能的格式。
^\d?(?:(?:[\+]?(?:[\d]{1,3}(?:[ ]+|[\-.])))?[(]?(?:[\d]{3})[\-/)]?(?:[ ]+)?)?(?:[a-zA-Z2-9][a-zA-Z0-9 \-.]{6,})(?:(?:[ ]+|[xX]|(i:ext[\.]?)){1,2}(?:[\d]{1,5}))?$
我们看过RegExLib吗?
输入美国电话号码带来了很多可能性。
事实证明,至少在北美,有一个针对此的规范,称为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+))?$
更好的选择...只是去除输入上的所有非数字字符(" x"和前导" +"符号除外),要小心,因为英国人倾向于以非标准格式+44(0)写数字。 ..
当被要求使用国际前缀时(在这种情况下,我们应该完全丢弃(0)
)。
然后,最终得到如下值:
12345678901 12345678901x1234 345678901x1234 12344678901 12345678901 12345678901 12345678901 +4112345678 +441234567890
然后,当我们显示时,请重新格式化内心内容。例如
1 (234) 567-8901 1 (234) 567-8901 x1234
我在一家市场研究公司工作,我们必须过滤所有类型的输入。我们太复杂了。只需剥离非字母数字字符,然后查看是否有扩展名。
为了进行进一步的分析,我们可以订阅众多提供商中的一个,该提供商将使我们可以访问有效号码的数据库,并告诉我们它们是座机还是手机,未连接等。这需要花钱。
是否可以显示4个单独的字段(区号,3位前缀,4位部分,扩展名),以便它们可以分别输入地址的每个部分,并且可以分别验证每个部分?这样,我们不仅可以简化验证过程,还可以将电话号码以更一致的格式存储在数据库中。
我们将很难使用一个/简单的正则表达式来处理国际号码,有关国际(甚至北美)电话号码的困难,请参阅此文章。
我们将需要解析前几位数字来确定国家/地区代码,然后根据国家/地区采取不同的操作。
除此之外,我们提供的清单不包括其他美国通用格式,以免出现首字母缩写1. 在美国,大多数手机都不需要它,并且它将开始使年轻一代感到困惑,除非他们进行了国际拨号。
我们已正确确定这是一个棘手的问题...
-亚当
我相信Number :: Phone :: US和Regexp :: Common(尤其是Regexp :: Common :: URI :: RFC2806的来源)Perl模块可以提供帮助。
可能应该更详细地说明问题,以说明验证数字的目的。例如,911在美国是有效数字,但911x不适用于x的任何值。这样一来,电话公司就可以计算出拨号的时间。在此问题上有几种变体。但是正则表达式不会检查区号部分,因此这似乎不是一个问题。
就像验证电子邮件地址一样,即使我们有一个有效的结果,也要等到尝试使用它才能知道它是否已分配给某人。
如果我们要验证用户输入,为什么不对结果进行归一化处理呢?如果用户输入了一个我们无法识别为有效数字的数字,请将该数字另存为输入内容,或者去除不正确的字符。 Number :: Phone :: Normalize Perl模块可能是灵感的来源。
尽管剥离所有空格的答案很简洁,但它并不能真正解决所提出的正则表达式问题。以我的测试脚本为例,该脚本下载一个网页并使用正则表达式提取所有电话号码。由于仍然需要正则表达式,因此我们最好让正则表达式完成所有工作。我想出了这个:
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包含分机号。我的测试脚本从Internet下载文件并在其中打印所有电话号码。
#!/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 [--]\n" if not defined ; print "match [-- ]\n" if defined ; } 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 \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*))?';
我的倾向是同意剥离数字并只接受最好的内容。也许要确保至少存在几个数字,尽管这样做确实禁止例如字母电话号码" ASK-JAKE"之类的东西。
几个简单的perl表达式可能是:
@f = /(\d+)/g; tr/0-9//dc;
使用第一个将数字组保持在一起,这可能会提供格式提示。用第二个小数字扔掉所有非数字。
是否担心可能需要暂停然后再输入更多键?还是像555-1212(等待哔哔声)123之类的东西?
如果我们在谈论表单验证,则由于国家和提供者标准的不同,用于验证正确含义以及正确数据的正则表达式将变得极其复杂。保持最新状态也很困难。
我将问题解释为寻找一种广泛有效的模式,这种模式可能在内部没有一致性,例如具有一组有效的数字,但没有验证中继线,交换机等是否为国家代码前缀的有效模式。
北美很简单,对于国际人来说,我更喜欢使用一种"惯用的"模式,该模式涵盖人们指定和记住其号码的方式:
^((((\(\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
由于我的经验仅限于北美,欧洲和一小部分亚洲地区,因此这可能会产生偏差。
我一直在同一个问题上挣扎,试图使我的应用程序成为未来的证明,但是这些家伙使我朝着正确的方向前进。我实际上不是在检查数字本身是否有用,我只是在尝试确保输入的一系列数字可能有扩展名,也可能没有扩展名。
最糟糕的情况是,如果用户不得不从XML文件中提取未格式化的号码,他们仍然只会将这些号码键入手机的数字键盘" 012345678x5"中,没有真正的理由保持美观。这种RegEx对我来说会是这样的:
\d+ ?\w{0,9} ?\d+
01234467扩展名123456
01234567x123456
01234567890
对格式字符进行替换,然后检查其余字符的电话有效性。在PHP中,
$replace = array( ' ', '-', '/', '(', ')', ',', '.' ); //etc; as needed preg_match( '/1?[0-9]{10}((ext|x)[0-9]{1,4})?/i', str_replace( $replace, '', $phone_num );
像这样破坏一个复杂的正则表达式可能同样有效,但要简单得多。
.*
如果用户想给我们他的电话号码,那么请相信他正确无误。如果他不想给你,那么强迫他输入一个有效的数字将把他发送到竞争对手的站点,或者让他输入一个适合我们正则表达式的随机字符串。我什至可能会想查找一个溢价率性别行的编号,然后输入该行。
我还将以下任何内容视为网站上的有效条目:
"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"
我写得最简单(尽管我不需要点)。
^([0-9\(\)\/\+ \-]*)$
如下所述,它仅检查字符,而不检查其结构/顺序
请注意,剥除()字符不适用于常见的英国数字书写风格:+44(0)1234 567890
,这意味着拨打国际号码:+ 441234567890
或者在英国拨打" 01234567890"