可通过replace()回调函数实现动态脱敏:利用捕获组区分敏感类型,在回调中按id、phone、card分支处理;结合offset和string做上下文判断;注意正则边界符避免误匹配。

可以通过 String.prototype.replace() 的第二个参数传入回调函数,根据匹配内容、位置、分组等上下文动态决定脱敏规则,实现比静态字符串更灵活的敏感信息处理。
回调函数的参数含义要清楚
当正则表达式带有捕获组或全局标志时,回调函数会收到多个参数:
- 第一个参数(match):整个匹配的字符串
- 中间参数($1, $2, ...):依次对应每个捕获组的内容(如果有)
- 倒数第二个参数(offset):本次匹配在原字符串中的起始索引
- 最后一个参数(string):原始输入字符串
例如:'ID:12345, phone:13812345678'.replace(/(\d{5})|(\d{11})/g, (m, g1, g2, offset) => g1 ? '*****' : '***' + m.slice(3)),就能对 5 位数字和 11 位手机号分别脱敏。
用分组区分不同敏感类型,统一回调中分支处理
把身份证号、手机号、银行卡号等不同格式写进一个正则的多个捕获组,再在回调里判断哪个组有值,执行对应逻辑:
const pattern = /(\d{17}[\dXx])|(^1[3-9]\d{9}$)|(\d{4}\s\d{4}\s\d{4}\s\d{4})/g;
text.replace(pattern, (match, id, phone, card) => {
if (id) return id.replace(/^(.{6})(?:\d{8})(.{4})$/, '$1********$2');
if (phone) return phone.replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2');
if (card) return card.replace(/\d(?=\d{4})/g, '*');
return match;
});
结合 offset 和 string 实现上下文感知脱敏
有时是否脱敏需看前后字符。比如只脱敏独立的手机号,不脱敏嵌在 URL 或邮箱里的数字串:
- 检查
offset > 0 && string[offset - 1] !== '@'排除邮箱前缀 - 检查
string.slice(offset + match.length, offset + match.length + 1)是否为标点或空格 - 甚至用
string.slice(0, offset).trimEnd().slice(-1)看前一个非空字符是否为=或:,避免脱敏配置值
注意全局匹配与非贪婪、边界符的配合
不加 ^、$ 或 \b 容易误匹配子串。例如匹配手机号时用 /1[3-9]\d{9}/g 会把 138123456789(12 位)也截出前 11 位;应改为 /(^|\s)1[3-9]\d{9}(?=\s|$)/g,并在回调中返回 fullMatch[1] + masked + (nextChar === ' ' ? ' ' : '') 保留原始空格结构。
回调方式脱敏本质是把“匹配什么”和“替换成什么”解耦,让替换逻辑可编程。关键在正则设计合理、回调参数利用充分、边界情况有兜底。











