从文本中精准提取手机号并脱敏: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. 可复用:封装为类,方便嵌入其他项目
相关推荐
小羊没烦恼!5 分钟前
浅谈SQL Server中的事务日志(二)----事务日志在修改数据时的角色
前端·数据库·后端·python·web安全·oracle
ss.li11 分钟前
rppg阅读笔记 2026.10.15
图像处理·python·计算机视觉
大貔貅喝啤酒22 分钟前
Unittest框架使用教程
自动化测试·python
一个简单的TTS开发者39 分钟前
中文TTS工具有哪些-8款主流方案横向对比
人工智能·后端·python·indextts
yunfanleo42 分钟前
temperature 详解:大模型采样参数原理、三种用法与工程实践
人工智能·python·rpa
CarIise1 小时前
Maven依赖传递与聚合工程
python·r语言·django
VidDown9 小时前
24fps 转 25fps 不只是改个数字:帧率转换、PAL/NTSC 与音频补偿
python·网络协议·音视频·视频编解码·视频
死磕音视频11 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
凤山老林12 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
pride.li13 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉