You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python正则表达式匹配电话号码异常:原因分析与修复方案

正则匹配电话号码的异常原因与修复方案

问题回顾

你尝试用Python正则表达式匹配电话号码,最初的实现代码如下:

import re
r = re.compile(r'''(\+)*\d* # optional + sign for international calls
([\" "-\)]{,1}\d+)* # main chain of numbers, numbers separated by a space, ) or a hyphen
''',re.VERBOSE)
print(r.findall('+00 0000 0000 is my number and +44-787-77950 was my uk number'))

你预期得到的结果是类似 [('+00',' 0000',' 0000'),('+44','-787','-77950')] 的分组元组,或是更简洁的 ['+00 0000 0000','+44-787-77950'],但实际返回了大量包含空字符串的异常元组:

[('+', ' 0000'), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('+', '44'), ('', ''), ('', '787'), ('', ''), ('', '77950'), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', '')]

后续你调整了正则表达式:

import re
r = re.compile(r'''(\+)?(\d+) # optional + sign for international calls
([\" "-\)]{,1}\d+)+ # main chain of numbers, numbers separated by a space, ) or a hyphen
''',re.VERBOSE)
print(r.findall('+00 0000 0000 is my number and +44-787-77950 was my uk number'))

但结果依然不符合预期:

[('+', '00', ' 0000'), ('+', '4', '4'), ('', '78', '7'), ('', '7795', '0')]

异常原因分析

咱们一步步拆解问题根源:

  1. 第一个正则的核心问题:

    • 你使用了*(零次或多次匹配)修饰捕获分组,比如(\+)*和([\" "-\)]{,1}\d+)*。注意:re.findall的规则是,如果正则包含捕获分组,会返回分组的匹配结果列表;若分组允许零次匹配,就会产生大量空字符串的捕获结果。
    • \d*会匹配零个数字,导致正则会在文本的空白、非数字字符处强制匹配,进一步增加了空结果的数量。
    • 字符集[\" "-\)]存在语法问题:单引号包裹的正则字符串里不需要转义双引号,且-放在字符集中间会被解析为范围符号,正确写法应为[ -)](把-放在开头或结尾,避免被识别为范围)。
  2. 第二个正则的核心问题:

    • 虽然把*改成了+(至少匹配一次),但([\" "-\)]{,1}\d+)+是重复的捕获分组。正则中重复的捕获分组只会保留最后一次匹配的内容,导致原本连续的数字段被错误拆分(比如44被拆成4和4)。
    • 没有对整个电话号码做整体匹配限制,导致正则会匹配文本中的零散数字片段,而非完整的号码。

修复方案

根据你的两种预期结果,分别给出针对性的解决方案:

方案1:获取完整的电话号码字符串(推荐)

如果你想要['+00 0000 0000','+44-787-77950']这种简洁结果,我们需要让正则匹配整个电话号码,并使用非捕获分组避免多余的分组捕获:

import re
r = re.compile(r'''
\+?                # 可选的+号,满足国际区号可选需求
\d+                # 号码开头的数字(至少1位,避免零匹配)
(?:[ -)]\d+)+      # 非捕获分组:匹配分隔符(空格/连字符/右括号)+数字,至少重复1次
''', re.VERBOSE)
print(r.findall('+00 0000 0000 is my number and +44-787-77950 was my uk number'))

运行结果:

['+00 0000 0000', '+44-787-77950']

方案2:获取拆分后的号码段元组

如果你想要[('+00',' 0000',' 0000'),('+44','-787','-77950')]的分组结果,需要先捕获完整的号码段,再拆分后续部分:

import re
r = re.compile(r'''
(\+?\d+)           # 捕获带+号的开头数字段(如+00、+44)
((?:[ -)]\d+)+)    # 捕获后续所有数字段的整体内容
''', re.VERBOSE)

matches = r.findall('+00 0000 0000 is my number and +44-787-77950 was my uk number')
# 拆分后续段并组合成目标格式
result = []
for start, rest in matches:
    parts = [start] + re.findall(r'[ -)]\d+', rest)
    result.append(tuple(parts))
print(result)

运行结果:

[('+00', ' 0000', ' 0000'), ('+44', '-787', '-77950')]

内容的提问来源于stack exchange,提问作者user160738

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:46:22