安全手机号掩码需先校验长度为11且全数字,再用replace(3,4,"**")处理;身份证脱敏须保留前6位、年份4位及末2位(含X校验码);string_view仅作只读输入以减少拷贝开销。

如何用 std::string 安全地做手机号掩码(11位→138****1234)
直接替换中间4位为 "****" 是最常见需求,但要注意边界:非11位字符串不能硬套,否则会破坏邮箱、身份证等其他格式。建议先用正则或长度+数字校验筛出疑似手机号,再处理。
实操建议:
- 用
str.length() == 11 && std::all_of(str.begin(), str.end(), ::isdigit)快速过滤,比正则轻量且无依赖 - 掩码位置固定为第4~7位(索引3~6),用
str.replace(3, 4, "****"),避免手动拼接引发越界 - 别用
str.substr(0,3) + "****" + str.substr(7)——当str长度不足7时,substr(7)返回空串但不报错,容易掩盖输入异常
身份证号脱敏为什么不能只截取前6后4?
18位身份证含地址码(前6)、出生日期(中间8)、顺序码和校验码(末4)。只留前后会泄露籍贯和大致年龄,不符合《个人信息安全规范》对“去标识化”的要求。
更稳妥的做法是:
立即学习“C++免费学习笔记(深入)”;
- 保留前6位(区域码)+ 第7~10位(年份,如1995)+ 后2位(校验码),中间出生月日、顺序码全部掩掉,例如
"1101011995****123X" - 用
std::regex_replace配合R"((\d{6})(\d{4})\d{8}(\w{2}))"提取关键段,注意\w要覆盖末位可能的X - 校验码必须保留——它参与原始ID有效性验证,删掉会导致下游系统校验失败
std::string_view 能否用于脱敏?性能差异有多大?
不能直接用于写操作,因为它是只读视图。想用它提速,只能作为输入参数避免拷贝,真正修改还得转回 std::string。
比如函数签名写成:
std::string mask_phone(std::string_view s) {
if (s.length() != 11) return std::string(s);
std::string res(s); // 这里一次拷贝不可避免
res.replace(3, 4, "****");
return res;
}
对比传值 std::string,省去了构造临时对象的开销,尤其对长文本(如日志行)有明显收益;但若原字符串本就短(
中文姓名脱敏为何不能简单取首字+“*”?
两字名(如“李四”)和三字名(如“欧阳修”)结构不同,硬套“首字+**”会暴露姓名长度信息。更隐蔽的方式是统一输出“姓+*”,并确保“*”数量与原名长度无关。
可行方案:
- 用
std::mbstowcs或 UTF-8 解码库(如utf8cpp)识别中文字符边界,避免单字节截断导致乱码 - 提取第一个 Unicode 字符(通常是姓),后面全替换成单个
"*",例如“张三丰”→“张*”,“司马相如”→“司*” - 如果业务允许,直接返回“某*”——既规避长度泄露,又无需解析编码,适合高吞吐日志场景
真正难的是混合场景:姓名里夹英文或数字(如“McDonald”、“张3丰”),这种必须结合业务规则定策略,通用算法大概率翻车。


















