用于电话号码验证的全面正则表达式

时间:2020-03-06 14:37:28  来源:igfitidea点击:

我正在尝试综合使用一个正则表达式来验证电话号码。理想情况下,它将处理国际格式,但必须处理美国格式,包括以下内容:

  • 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"