【问题标题】:Python Regex: US phone number parsingPython Regex:美国电话号码解析
【发布时间】:2021-11-10 22:00:23
【问题描述】:

我是正则表达式的新手。

我需要将不同格式的美国电话号码解析为 3 个字符串:区号(没有“()”)、接下来的 3 位数字、最后 4 位数字。没有'-'。

我也需要拒绝(消息错误):

916-111-1111(区号后有'-') (916)111 -1111(“-”之前的空格) (916)111-1111(区号内的任何空格) - (916) - 必须是 也被拒绝了

(a56)111-1111(区号内的任何非数字)

区号缺少“()”

应该没问题:'(916) 111-1111'(除上述之外的任何地方的空格)

这是我的正则表达式:

^\s*\(?(\d{3})[\)\-][\s]*?(\d{3})[-]?(\d{4})\s*$

这花了我 2 天时间。

它没有失败 916-111-1111(区号后有“-”的可用性)。我敢肯定还有其他一些不足之处。

非常感谢您的帮助。甚至提示。

有效:

'(916) 111-1111'
'(916)111-1111     '
'   (916)      111-1111'

无效:

'916-111-1111' - no () or '-' after area code
'(916)111 -1111' - no space before '-'
'( 916)111-1111' - no space inside ()
'(abc) 111-11i1' because of non-digits

【问题讨论】:

    标签: python regex parsing


    【解决方案1】:

    如果您考虑 (1) 提供简单的用户界面而不是要求用户修改输入或 (2) 将数字存储到后端存储,则可以简化正则表达式,如下所示:

    "(\d{1,3})\D*(\d{3})\D*(\d{4})"
    

    由于您要打印错误信息,因此应根据错误信息重新检查找到的正则表达式组,如下所示:

    代码:

    import re
    
    def get_failed_reason(s):
        space_regex = r"(\s+)"
        area_code_regex = r"\s*(\D*)(\d{1,3})(\D*)(\d{3})(\D*)-(\d{4})"
        results = re.findall(area_code_regex, s)
        if 0 == len(results):
            area_code_alpha_regex = r"\((\D+)\)"
            results = re.findall(area_code_alpha_regex, s)
            if len(results) > 0:
                return "because of non-digits"
            return "no matches"
        results = results[0]
    
        space_results = re.findall(space_regex, results[0])
        if 0 == len(space_results):
            space_results = re.findall(space_regex, results[2])
        if 0 != len(space_results):
            return "no space inside ()"
        
        alpha_code_regex = r"(\D+)"
        alpha_results = re.findall(alpha_code_regex, results[0])
        if 0 == len(alpha_results):
            alpha_results = re.findall(alpha_code_regex, results[2])
        if 0 != len(alpha_results):
            if "(" not in results[0] or ")" not in results[2]:
                return "no () or '-' after area code"
            if 0 != len(results[-2]):
                return "no space before '-'"
            return "because of non-digits in area code"
        return "unspecified"
    
    if __name__ == '__main__':
        phone_numbers = ["916-111-1111", "(916)111-1111", "(916)111 -1111     ", "   (916)      111-1111", "(916 )111-1111", "( 916)111-1111", "- (916 )111-1111",  "(a56)111-1111", "(56a)111-1111", "(916) 111-1111    ", "(abc) 111-1111"]
        valid_regex = r"\s*(\()(\d{1,3})(\))(\D*)(\d{3})([^\d\s]*)-(\d{4})"
        for phone_number_str in phone_numbers:
            results = re.findall(valid_regex, phone_number_str)
                
            if 0 == len(results):
                reason = get_failed_reason(phone_number_str)
                phone_number_str = f"[{phone_number_str}]"
                print(f"[main] Failed:\t{phone_number_str: <30}- {reason}")
                continue
            area_code = results[0][1]
            first_number = results[0][4]
            second_number = results[0][6]
            phone_number_str = f"[{phone_number_str}]"
            print(f"[main] Valid:\t{phone_number_str: <30}- Area code: {area_code}, First number: {first_number}, Second number: {second_number}")
    

    结果:

    [main] Failed:  [916-111-1111]                - no () or '-' after area code
    [main] Valid:   [(916)111-1111]               - Area code: 916, First number: 111, Second number: 1111
    [main] Failed:  [(916)111 -1111     ]         - no space before '-'
    [main] Valid:   [   (916)      111-1111]      - Area code: 916, First number: 111, Second number: 1111
    [main] Failed:  [(916 )111-1111]              - no space inside ()
    [main] Failed:  [( 916)111-1111]              - no space inside ()
    [main] Failed:  [- (916 )111-1111]            - no space inside ()
    [main] Failed:  [(a56)111-1111]               - because of non-digits in area code
    [main] Failed:  [(56a)111-1111]               - because of non-digits in area code
    [main] Valid:   [(916) 111-1111    ]          - Area code: 916, First number: 111, Second number: 1111
    [main] Failed:  [(abc) 111-1111]              - because of non-digits
    

    注意:D 表示非数字字符。

    【讨论】:

    • 您的代码返回所有情况的结果,但根据 OP 原理,它们都是错误的
    • @diggusbickus 好吧,我更新了答案以按照 OP 的要求打印错误消息。
    • 关键不是打印消息,而是您的正则表达式完成了这项工作。你的 valid_regex 看起来不错,但旧的失败了,你的消息 (You can simplify the regex as follows) 具有误导性
    • @diggusbickus 我的简化正则表达式的初衷在更新的答案中进行了解释。
    【解决方案2】:

    你可以这样做:

    import re
    r = r'\((\d{3})\)\s*?(\d{3})\-(\d{4,5})'
    l = ['(916) 111-11111', '(916)111-1111     ', '   (916)      111-1111', '916-111-1111', '(916)111 -1111', '( 916)111-1111', '(abc) 111-11i1']
    print([re.findall(r, x) for x in l])
    
    # [[('916', '111', '11111')], [('916', '111', '1111')], [('916', '111', '1111')], [], [], [], []]
    

    【讨论】:

      猜你喜欢
      • 2011-03-22
      • 2011-05-22
      • 1970-01-01
      • 2015-01-19
      • 2012-05-22
      • 2010-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多