正则与字典实战问题:提取并分组带区号的电话号码
如何提取指定格式电话号码并生成对应字典
需求说明
需要提取文本中的电话号码,规则如下:
- 区号格式为
+加3位数字,区号与号码间可有可无空格; - 电话号码本身为7-8位数字;
- 无区号的7-8位号码需归类到空字符串
''对应的键下。
现有代码
def find_phone_numbers(text: str) -> dict: pattern = r'\+\w{3} \w{8}|\+\w{11}|\+\w{3} \w{7}|\+\w{10}|\w{8}|\w{7}' match = re.findall(pattern, text) str1 = " " phone_str = str1.join(match) phone_dict = {} phones = phone_str.split(" ") for phone in phones: if phone[0] == "+": phone0 = phone if phone_str[0:4] not in phone_dict.keys(): phone_dict[phone_str[0:4]] = [phone_str[5:]] return phone_dict
预期输出
print(find_phone_numbers("+372 56887364 +37256887364 +33359835647 56887364 +11 1234567 +327 1 11111111")) -> {'+372': ['56887364', '56887364'], '+333': ['59835647'], '': ['56887364', '1234567', '11111111']}
核心问题
无法正确处理区号与号码连写的格式(如+33359835647),无法剥离区号与号码部分,同时现有实现逻辑混乱,无法对同区号号码分组。
解决方案
1. 优化正则表达式
使用捕获组分别匹配区号和号码,一次性处理带空格/无空格的带区号号码,以及无区号号码:
r'(\+\d{3})\s?(\d{7,8})|(\d{7,8})'
- 第一组
(\+\d{3}):捕获带+的3位区号; \s?:匹配0或1个空格(处理区号与号码间有无空格的情况);- 第二组
(\d{7,8}):捕获带区号的7-8位号码; - 第三组
(\d{7,8}):捕获无区号的7-8位号码。
2. 高效实现代码
import re def find_phone_numbers(text: str) -> dict: pattern = r'(\+\d{3})\s?(\d{7,8})|(\d{7,8})' matches = re.findall(pattern, text) phone_dict = {} for area_code_part, number_with_area, number_no_area in matches: # 确定当前号码的区号和号码内容 area_code = area_code_part if area_code_part else '' current_number = number_with_area if number_with_area else number_no_area # 跳过空匹配(避免无效数据) if not current_number: continue # 维护字典:同区号号码追加到列表 if area_code not in phone_dict: phone_dict[area_code] = [] phone_dict[area_code].append(current_number) # 确保空字符串键存在(按预期输出逻辑保留) if '' not in phone_dict: phone_dict[''] = [] return phone_dict
代码说明
- 遍历所有正则匹配结果,通过捕获组判断号码类型(带区号/无区号);
- 动态维护字典,自动为新增的区号创建键,并将同区号号码追加到对应列表;
- 跳过无效匹配,避免空字符串干扰结果;
- 兼容所有需求格式,包括连写的
+33359835647(提取出区号+333,号码59835647)。
测试验证
运行示例输入,输出与预期完全一致:
{'+372': ['56887364', '56887364'], '+333': ['59835647'], '': ['56887364', '1234567', '11111111']}
内容的提问来源于stack exchange,提问作者QLimbo
相关产品推荐
相关产品推荐

