从文本中精准提取手机号并脱敏:Python 正则 + 文件流的实战进阶

日常处理用户数据时,"识别文本中的手机号并对中间位打码" 是高频需求 ------ 但直接写正则可能踩坑(比如匹配到 11 位数字但不是手机号),文件读写也容易忽略编码和资源泄漏问题。

这篇文章带你从规则分析→正则优化→文件安全操作→异常处理,写一个更健壮的手机号脱敏工具。

一、先明确:手机号的 "合法规则" 是什么?

国内手机号不是 "任意 11 位数字",而是有明确号段限制:

  • 开头为1,第二位是3-9(覆盖 13/14/15/16/17/18/19 号段)
  • 总长度严格 11 位
  • 不能是 "类似手机号的数字串"(比如快递单号里的 11 位数字)

二、第一步:写一个 "不踩坑" 的手机号正则

直接用1\d{10}会匹配到非手机号的 11 位数字,我们需要精准匹配号段

python 复制代码
# 精准匹配国内手机号(覆盖所有主流号段)
PHONE_PATTERN = re.compile(r'1[3-9]\d{9}')
  • 1:固定开头
  • [3-9]:限制第二位为 3-9(排除 10/11/12 开头的无效号段)
  • \d{9}:后续 9 位数字(总长度 11 位)

三、第二步:安全的文件读写逻辑

直接用open()容易忘记关文件,或者遇到中文乱码 ------ 用with上下文管理器 + 指定编码是最佳实践:

python 复制代码
def read_text_file(file_path: str) -> str:
    """安全读取文本文件,处理编码和文件不存在异常"""
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            return f.read()
    except FileNotFoundError:
        raise ValueError(f"错误:文件{file_path}不存在")
    except UnicodeDecodeError:
        raise ValueError(f"错误:文件{file_path}编码不是UTF-8,请检查")

def write_text_file(file_path: str, content: list[str]) -> None:
    """安全写入文本文件,每行一个内容"""
    with open(file_path, 'w', encoding='utf-8') as f:
        f.write('\n'.join(content))

四、第三步:实现 "提取 + 打码" 的核心逻辑

结合正则匹配和文件操作,完成从 "读文本" 到 "输出脱敏结果" 的全流程:

python 复制代码
import re
from typing import List

class PhoneDesensitizer:
    def __init__(self):
        # 初始化手机号正则(预编译提升效率)
        self.phone_pattern = re.compile(r'1[3-9]\d{9}')

    def extract_phones(self, text: str) -> List[str]:
        """从文本中提取所有合法手机号"""
        return self.phone_pattern.findall(text)

    def mask_phones(self, phones: List[str]) -> List[str]:
        """对手机号中间4位打码(前3后4保留,中间替换为****)"""
        return [f"{phone[:3]}****{phone[7:]}" for phone in phones]

    def process_file(self, input_path: str, output_path: str) -> None:
        """完整流程:读文件→提取手机号→打码→写文件"""
        # 1. 读取原始文本
        raw_text = read_text_file(input_path)
        # 2. 提取合法手机号
        original_phones = self.extract_phones(raw_text)
        if not original_phones:
            print("未识别到任何手机号")
            return
        # 3. 打码处理
        masked_phones = self.mask_phones(original_phones)
        # 4. 写入结果文件
        write_text_file(output_path, masked_phones)
        print(f"处理完成!共脱敏{len(masked_phones)}个手机号,结果已保存到{output_path}")

五、完整使用示例

python 复制代码
if __name__ == "__main__":
    # 初始化脱敏工具
    desensitizer = PhoneDesensitizer()
    # 替换为你的实际文件路径
    desensitizer.process_file(
        input_path="用户数据.txt",
        output_path="脱敏后_用户手机号.txt"
    )

效果演示

  • 原始文件用户数据.txt

    python 复制代码
    客户1:13812345678(北京),客户2:19987654321(上海)
    备注:订单号20231234567(注意:这是11位数字但不是手机号,不会被匹配)
  • 输出文件脱敏后_用户手机号.txt

    python 复制代码
    138****5678
    199****4321

六、进阶优化:避免匹配 "非手机号的 11 位数字"

如果文本中存在类似 "订单号" 的 11 位数字,可以通过前后非数字约束进一步精准匹配:

python 复制代码
# 优化正则:要求手机号前后不是数字(避免匹配数字串中的11位片段)
PHONE_PATTERN = re.compile(r'(?<!\d)1[3-9]\d{9}(?!\d)')
  • (?<!\d):断言手机号前面不是数字
  • (?!\d):断言手机号后面不是数字

总结

这个工具的核心亮点:

  1. 正则精准:覆盖所有合法号段,避免匹配无效数字;
  2. 文件安全 :处理编码和异常,用with保证资源不泄漏;
  3. 可复用:封装为类,方便嵌入其他项目
相关推荐
BBB努力学习程序设计2 小时前
Python文件操作完全指南:读写文件与数据处理
python·pycharm
vv_Ⅸ2 小时前
打卡day47
python
zhongtianhulian2 小时前
陶瓷行业大会资讯:掌握行业动态,洞察未来趋势
大数据·人工智能·python
小鸡吃米…2 小时前
Python的人工智能-入门指南
python
LT>_<2 小时前
flink遇到的问题
大数据·python·flink
写代码的【黑咖啡】3 小时前
面向对象编程入门:从类与对象到构造函数
开发语言·python
luo_yu_11063 小时前
安装chroma的时候报错
python·chroma
Daily Mirror3 小时前
Day 43 训练和测试的规范写法
python
natide3 小时前
词汇/表达差异-7-Alias覆盖率
人工智能·pytorch·python·深度学习·自然语言处理