如何使用正则表达式验证电话号码

1054

我正在尝试编写一个全面的正则表达式来验证电话号码。理想情况下,它将处理国际格式,但必须处理美国格式,包括以下格式:

  • 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

我会回答我的当前尝试,但我希望有人能提供更好和/或更优雅的解决方案。


2
此答案已添加到Stack Overflow正则表达式FAQ,位于“常见验证任务”下。 - aliteralmind
不幸的是,访问那个页面并搜索“常见验证任务”没有任何结果… - Lewis Cianci
这是一个正则表达式任务吗? - Guildenstern
在某些情况下,这是一个 XY 问题。你要求一个谓词,如果电话号码有效则返回 True,但你真正想要的只是一个正确的电话号码。对于任何试图清理网页或手机应用程序中最终用户输入的电话号码的人,我建议只需编写4或5行代码,逐个字符从左到右进行处理并且删除所有非数字字符。(303)873-9919 变成了 3038739919。删除所有非数字字符后,您可以在正确的位置插入(点 .),插入(连字符 -)或斜杠。 - Samuel Muldoon
45个回答

2

我倾向于认同只保留数字并接受现有数据的做法。也许可以确保至少有几个数字存在,尽管这样会阻止像“ASK-JAKE”这样的字母电话号码。

一些简单的Perl表达式可能是:

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

使用第一个方法将数字组合在一起,这可能会提供格式化提示。使用第二个方法可以轻松地丢弃所有非数字字符。

如果需要暂停然后输入更多按键,或者像555-1212(等待哔声)123这样的情况是否令人担忧?


1
由于此帖子没有语言标签,我将提供在Python中使用的正则表达式解决方案。
表达式本身:
1[\s./-]?\(?[\d]+\)?[\s./-]?[\d]+[-/.]?[\d]+\s?[\d]+

当在Python中使用时:

import re

phonelist ="1-234-567-8901,1-234-567-8901 1234,1-234-567-8901 1234,1 (234) 567-8901,1.234.567.8901,1/234/567/8901,12345678901"

phonenumber = '\n'.join([phone for phone in re.findall(r'1[\s./-]?\(?[\d]+\)?[\s./-]?[\d]+[-/.]?[\d]+\s?[\d]+' ,phonelist)])
print(phonenumber)

输出:

1-234-567-8901
1-234-567-8901 1234
1-234-567-8901 1234
1 (234) 567-8901
1.234.567.8901
1/234/567/8901
12345678901

1

使用简单的正则表达式处理各种国际电话号码几乎是不可能的。

最好使用像numverify.com这样的服务,他们提供免费的JSON API用于国际电话号码验证,每次请求还会得到有关国家、位置、运营商和线路类型的一些有用详细信息。


1
我不建议使用正则表达式来完成这个任务。
像顶部答案一样,去掉电话号码中所有的杂质,以便你只留下一个由数字字符组成的字符串,如果有分机号,则包括一个 'x'。
在Python中:
注意:BAD_AREA_CODES来自一个文本文件text file,你可以从网络上获取。
BAD_AREA_CODES = open('badareacodes.txt', 'r').read().split('\n')

def is_valid_phone(phone_number, country_code='US'):
    """for now, only US codes are handled"""
    if country_code:
        country_code = country_code.upper()

    #drop everything except 0-9 and 'x'
    phone_number = filter(lambda n: n.isdigit() or n == 'x', phone_number)

    ext = None
    check_ext = phone_number.split('x')
    if len(check_ext) > 1:
        #there's an extension. Check for errors.
        if len(check_ext) > 2:
            return False
        phone_number, ext = check_ext

    #we only accept 10 digit phone numbers.
    if len(phone_number) == 11 and phone_number[0] == '1':
        #international code
        phone_number = phone_number[1:]
    if len(phone_number) != 10:
        return False

    #area_code: XXXxxxxxxx 
    #head:      xxxXXXxxxx
    #tail:      xxxxxxXXXX
    area_code = phone_number[ :3]
    head      = phone_number[3:6]
    tail      = phone_number[6: ]

    if area_code in BAD_AREA_CODES:
        return False
    if head[0] == '1':
        return False
    if head[1:] == '11':
        return False

    #any other ideas?
    return True

这涵盖了相当多的内容。虽然它不是正则表达式,但它很容易映射到其他语言。

1

土耳其的工作示例,只需更改

d{9}

根据您的需求开始使用它。
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!';
}

0

尝试这个(它是用于印度手机号码验证的):

if (!phoneNumber.matches("^[6-9]\\d{9}$")) {
  return false;
} else {
  return true;
}

为什么不直接返回matches的输出呢? - nice_dev

0

虽然它不是正则表达式,但你可以使用 Python 库 DataPrep 中的函数 validate_phone() 来验证美国电话号码。使用 pip install dataprep 命令安装它。

>>> from dataprep.clean import validate_phone
>>> df = pd.DataFrame({'phone': ['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, '12345678', '123-456-78987']})
>>> validate_phone(df['phone'])
0     True
1     True
2     True
3     True
4     True
5     True
6     True
7    False
8    False
Name: phone, dtype: bool

0

注意:该函数接受任何格式的美国手机号码作为输入,并可选择接受第二个参数 - 如果您想要输出的手机号码格式看起来漂亮,则将其设置为 true。如果提供的号码不是手机号码,则简单地返回 false。如果检测到手机号码,则返回整个经过清理的号码,而不是 true。

    function isValidMobile(num,format) {
        if (!format) format=false
        var m1 = /^(\W|^)[(]{0,1}\d{3}[)]{0,1}[.]{0,1}[\s-]{0,1}\d{3}[\s-]{0,1}[\s.]{0,1}\d{4}(\W|$)/
        if(!m1.test(num)) {
           return false
        }
        num = num.replace(/ /g,'').replace(/\./g,'').replace(/-/g,'').replace(/\(/g,'').replace(/\)/g,'').replace(/\[/g,'').replace(/\]/g,'').replace(/\+/g,'').replace(/\~/g,'').replace(/\{/g,'').replace(/\*/g,'').replace(/\}/g,'')
        if ((num.length < 10) || (num.length > 11) || (num.substring(0,1)=='0') || (num.substring(1,1)=='0') || ((num.length==10)&&(num.substring(0,1)=='1'))||((num.length==11)&&(num.substring(0,1)!='1'))) return false;
        num = (num.length == 11) ? num : ('1' + num);   
        if ((num.length == 11) && (num.substring(0,1) == "1")) {
            if (format===true) {
               return '(' + num.substr(1,3) + ') ' + num.substr(4,3) + '-' + num.substr(7,4)
            } else {
               return num
            }
        } else {
            return false;
        }
    }

0

Java 生成用于验证电话号码的正则表达式(REGEX)

另一种选择是让 Java 生成一个 REGEX,匹配从列表中读取的所有电话号码变体。这意味着在下面的代码上下文中看到的名为 validPhoneNumbersFormat 的列表决定哪种电话号码格式是有效的。

注意:这种类型的算法适用于处理正则表达式的任何语言。

生成 REGEX 的代码片段:

Set<String> regexSet = uniqueValidPhoneNumbersFormats.stream()
        .map(s -> s.replaceAll("\\+", "\\\\+"))
        .map(s -> s.replaceAll("\\d", "\\\\d"))
        .map(s -> s.replaceAll("\\.", "\\\\."))
        .map(s -> s.replaceAll("([\\(\\)])", "\\\\$1"))
        .collect(Collectors.toSet());

String regex = String.join("|", regexSet);

代码片段上下文:

public class TestBench {

    public static void main(String[] args) {
        List<String> validPhoneNumbersFormat = Arrays.asList(
                "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",
                "+12345678901",
                "(234) 567-8901 ext. 123",
                "+1 234-567-8901 ext. 123",
                "1 (234) 567-8901 ext. 123",
                "00 1 234-567-8901 ext. 123",
                "+210-998-234-01234",
                "210-998-234-01234",
                "+21099823401234",
                "+210-(998)-(234)-(01234)",
                "(+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"
        );

        Set<String> uniqueValidPhoneNumbersFormats = new LinkedHashSet<>(validPhoneNumbersFormat);

        List<String> invalidPhoneNumbers = Arrays.asList(
                "+210-99A-234-01234",       // FAIL
                "+210-999-234-0\"\"234",    // FAIL
                "+210-999-234-02;4",        // FAIL
                "-210+998-234-01234",       // FAIL
                "+210-998)-(234-(01234"     // FAIL
        );
        List<String> invalidAndValidPhoneNumbers = new ArrayList<>();
        invalidAndValidPhoneNumbers.addAll(invalidPhoneNumbers);
        invalidAndValidPhoneNumbers.addAll(uniqueValidPhoneNumbersFormats);

        Set<String> regexSet = uniqueValidPhoneNumbersFormats.stream()
                .map(s -> s.replaceAll("\\+", "\\\\+"))
                .map(s -> s.replaceAll("\\d", "\\\\d"))
                .map(s -> s.replaceAll("\\.", "\\\\."))
                .map(s -> s.replaceAll("([\\(\\)])", "\\\\$1"))
                .collect(Collectors.toSet());

        String regex = String.join("|", regexSet);

        List<String> result = new ArrayList<>();
        Pattern pattern = Pattern.compile(regex);
        for (String phoneNumber : invalidAndValidPhoneNumbers) {
            Matcher matcher = pattern.matcher(phoneNumber);
            if(matcher.matches()) {
                result.add(matcher.group());
            }
        }

        // Output:
        if(uniqueValidPhoneNumbersFormats.size() == result.size()) {
            System.out.println("All valid numbers was matched!\n");
        }    
        result.forEach(System.out::println); 
    }

}

输出:

All valid numbers was matched!

1-234-567-8901
1-234-567-8901 x1234
1-234-567-8901 ext1234
...
...
...

0

我选择了下面的正则表达式,但是当我复制和粘贴电话号码时它没有起作用。

/^(\+?\d{0,4})?[ -]?(\(?\d{3}\)?)[ -]?(\(?\d{3}\)?)[ -]?(\(?\d{4}\)?)?$/

原因是有一个不同的破折号符号(这个而不是-)。所以我又修改了正则表达式,将它也加进去了。
/^(\+?\d{0,4})?[ -‑]?(\(?\d{3}\)?)[ -‑]?(\(?\d{3}\)?)[ -‑]?(\(?\d{4}\)?)?$/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接