AC自动机是唯一兼顾正确性、吞吐量与内存可控性的方案,因其O(n+z)匹配复杂度、支持重叠嵌套匹配、UTF-8安全解析及预分配内存等特性,显著优于暴力扫描。

别用 std::string::find 或循环 replace,它们在词量超百、文本超几 KB 时就明显卡顿,且必然漏匹配、错掩码、崩 UTF-8;AC 自动机是唯一能兼顾正确性、吞吐量和内存可控性的方案。
为什么 AC 自动机比暴力扫描快一个数量级
暴力扫描时间复杂度是 O(n × m),n 是文本长度,m 是敏感词数量;AC 自动机建树耗时 O(Σ|word|),匹配仅 O(n + z)(z 是总匹配数),10KB 文本 + 2000 个词实测匹配耗时稳定在 5–12μs。关键在于它把所有词编译成一张状态跳转表,单次扫描就能命中全部重叠/嵌套项,比如“南京”和“南京市”在“南京市鼓楼区”中可同时定位,无需回溯或重复扫描。
-
std::string::find每次从头开始扫,遇到“张三丰”,先匹配“张三”切掉,后续“三丰”就再也找不到 - AC 自动机靠 failure link 和 output chain 实现“匹配不中断”,同一位置可输出多个词 ID
- 手写简化版 AC 可全用
std::array预分配状态节点(如std::array<node></node>),避免new和std::vector动态扩容,内存占用固定可估
如何避免 UTF-8 中文被截断成乱码
所有掩码操作必须基于字节偏移对齐,但 std::string 的 substr(pos, len) 和 replace(pos, len, ...) 默认按字节操作——若 pos 落在某个汉字中间(如 UTF-8 中“宝”占 3 字节,s[5] 正好是第二字节),就会破坏编码。不能靠猜,得显式解析。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 匹配前不做任何大小写转换:AC 库默认按字节比较,中文转小写会出错;如需 case-insensitive,统一用
std::tolower处理原始词表再建树 - 拿到 AC 返回的
{start_byte, length_byte}后,**不直接切片**;用utf8cpp::distance(s.c_str(), s.c_str() + start_byte)算出起始码点位置,再用utf8cpp::advance得到结束码点,反向映射回字节区间 - 掩码字符串必须等长:用
std::string(length_byte, '*'),而非硬写"***";“张三”占 6 字节,就得填 6 个*
怎么安全拼接结果串而不触发多次 realloc
边匹配边 += 拼接是性能杀手——每次 += 都可能触发 realloc 和整块拷贝。高频脱敏场景下,90% 耗时其实不在匹配,而在字符串构造。
立即学习“C++免费学习笔记(深入)”;
- 先用
std::vector<:pair size_t>></:pair>存所有{start, end}字节区间,按end降序排序(std::sort(matches.rbegin(), matches.rend())) - 预估结果容量:
result.reserve(text.size() + 2 * matches.size())(每个掩码平均多 1–2 字节) - 倒序遍历区间:从文本末尾往前拼,用
std::copy写入预分配 buffer,避免索引偏移问题;例如text.substr(end, text.size() - end)→ 掩码 →text.substr(start, end - start)→ 前段 - 禁用
std::string::append或+=在循环内;改用std::string_view提取子串,延迟拷贝
哪些地方最容易忽略导致线上崩溃
AC 自动机本身很稳,但周边环节一松懈就崩:failure link 没 BFS 初始化、UTF-8 区间没校验、掩码长度没对齐字节——这些错误在线下小数据测不出,一上生产就偶发乱码或越界访问。
- 构建后必须调用
ac.build_failure_links()或等效初始化函数,否则“南京路”里只命中“南京”,漏掉“京” - 敏感词插入前去重:
std::unordered_set<:string></:string>过滤,否则相同词建多次状态,浪费空间且 fail 指针逻辑错乱 - HTML 标签必须跳过:不解析 DOM,用双状态机识别
和 <code>>区间,在标签内不调用ac.search();否则<p>张三</p>会被替成<***>张三</***> - 替换后绝不检查新敏感词:AC 是单趟扫描,不支持“替换→再扫描”迭代;业务上需明确要求“仅原始文本脱敏”,避免引入逻辑循环


















