手机号脱敏应优先提取连续11位数字,用正则(\d{3})\d{4}(\d{4})捕获前后段替换为$1****$2;身份证需区分15位与18位(末位X大小写均支持),建议先粗略提取再按长度决定遮蔽位数;所有正则须预编译为全局变量复用,避免重复编译开销。

手机号脱敏:用 regexp.ReplaceAllString 保留前3后4位
手机号脱敏最常见需求是显示为 138****1234,核心是匹配11位数字并替换中间4位。别直接写 ^1[3-9]\d{9}$ 做全匹配校验再处理——脱敏不是校验,要容忍脏数据(比如带空格、括号、+86前缀)。实际应优先提取连续11位数字,再做替换。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用正则
(\d{3})\d{4}(\d{4})捕获前后两段,替换为$1****$2,比用ReplaceAllStringFunc更安全(避免误替换单独出现的11位数字) - 若输入含多个手机号(如日志文本),需用
regexp.MustCompile编译一次复用,否则每次调用都编译开销大 - 注意中文括号、全角数字等边界情况——
\d默认只匹配 ASCII 数字,要支持全角需改用[0-9\uFF10-\uFF19]
身份证号脱敏:区分15位与18位,末尾X要保留
18位身份证最后一位可能是 X(罗马数字10),不能简单用 \d{17} 匹配。错误写法如 \d{15}(\d{2}\d|X) 会漏掉15位老证;更糟的是把 X 当普通字符替换掉,导致校验失败。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用正则
(\d{6})\d{10}(\d{2}[\dxX])匹配18位(允许末位大小写X),或(\d{6})\d{6}(\d{3})匹配15位,分别处理 - 推荐统一用
(\d{6})\d{8,10}(\d{2,4}[\dxX]?)粗略提取,再用len()判长度决定遮蔽逻辑:15位遮中间6位,18位遮中间8位 - 别用
strings.Replace直接按位置切片——身份证可能带换行、空格,先strings.TrimSpace再处理
性能陷阱:正则编译开销和重复匹配
高频日志脱敏场景下,每条记录都 regexp.Compile 会导致 GC 压力飙升。Go 的 regexp 包不是线程安全的,但编译后的 *regexp.Regexp 实例可并发使用。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 所有正则必须提前用
var phoneReg = regexp.MustCompile(<code>...)全局变量声明,禁止在函数内编译 - 若需同时处理手机号+身份证,不要写成两个独立
ReplaceAllString调用——合并为一个正则用分组标识类型,减少字符串扫描次数 - 对纯数字字段(如数据库导出CSV),比正则更快的方式是:先
strconv.ParseInt尝试转整数,成功则按位数判断是否为身份证/手机号,避免正则回溯
边界情况:嵌套、部分匹配与零宽断言失效
用户输入 我的电话是13812341234,备用号159****5678,若正则没加单词边界,可能把 12341234 中间一段误当手机号;更隐蔽的是 id=11010119900307231X 这种键值对,= 后紧贴身份证号,^ 和 $ 完全失效。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用
(? 和 <code>(?!\d)零宽断言限制前后非数字,比\b更可靠(\b对中文无效) - 遇到
***138****1234***这类已部分脱敏的数据,先清洗再处理,否则双重脱敏变成***138****1234*** → ***138****1234*** - 日志中常见
phone=13812341234&id=110...这种URL参数,建议先用url.ParseQuery解析,再对特定 key 脱敏,比全文正则更精准
脱敏逻辑越贴近真实数据形态,越容易漏掉半角/全角混杂、不可见字符、URL编码这些细节。正则只是工具,关键在理解数据从哪来、到哪去。


















