AC自动机必须用failure link+output chain才能正确处理重叠词,仅建Trie树会漏匹配;构建需BFS、output为vector、插入前去重并按长度升序排序。

AC自动机必须用 failure link + output chain 才能正确处理重叠词
只建 Trie 树不够,比如词库含 "南京" 和 "京",输入 "南京路" 时,若无 failure link,只能匹配到 "南京";加上 failure link 并配置 output chain 后,节点 '京' 才能在匹配完 "南京" 后继续输出 "京"。否则必然漏匹配。
实操要点:
- 构建 failure link 必须用 BFS,不能 DFS —— DFS 容易导致父节点 fail 指针未就绪就计算子节点
- 每个节点的
output字段必须是 vector(不是单个 bool),用于存所有以该节点结尾的词 ID - failure link 跳转后要合并 output:即
node->output.insert(node->output.end(), node->fail->output.begin(), node->fail->output.end()) - 插入敏感词前先去重:
std::unordered_set<:string></:string>过滤空串和重复项
敏感词插入顺序影响 failure link 正确性
如果词库含 "色" 和 "色情",必须先插 "色" 再插 "色情"。否则 "色情" 的末节点 fail 指针可能指向根,跳过 "色",导致“色情网站”里只命中长词、漏掉短词。
原因在于 failure link 构建时依赖已存在路径:短词先入树,长词在匹配失败时才能沿 fail 指针落到短词终点。
立即学习“C++免费学习笔记(深入)”;
建议做法:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 按敏感词长度升序排序后再批量插入:
std::sort(keywords.begin(), keywords.end(), [](const auto& a, const auto& b) { return a.size() - 避免运行时动态增删——重建 AC 自动机需加锁,高并发下延迟突增
- 若需热更新,改用双实例切换:新词表建好新 automaton,原子指针替换,旧实例延迟析构
UTF-8 文本下必须做码点对齐,否则掩码会截断汉字
std::string 是字节数组,"张" 在 UTF-8 中占 3 字节。若 AC 自动机返回字节偏移 start=5、len=2,直接 text.substr(5, 2) 会取到半个汉字,结果乱码。
安全做法是:拿到字节区间后,用 utf8cpp::distance 和 utf8cpp::advance 映射到码点位置,再反推严格对齐的字节边界。
更稳妥的路径:
- 预处理阶段统一转
std::u32string:utf8cpp::utf8to32(text.begin(), text.end(), std::back_inserter(u32text)) - AC 自动机节点用
char32_t建树(或封装为uint32_t),完全规避多字节问题 - 掩码字符串也用
std::u32string(len_codepoints, U'*'),最后再转回 UTF-8 输出
匹配结果合并与字符串构造最容易崩性能
拿到一堆 {start_byte, length_byte} 后,若用 for 循环调用 text.replace(),每次都会触发内存 realloc,10KB 文本 + 50 个匹配,实测耗时从 12μs 暴涨到 8ms。
真正高效的做法是预分配 + 倒序拼接:
- 把所有匹配区间转成
std::vector<:pair size_t>></:pair>(存{start, end}字节位置) - 按
end降序排序:std::sort(matches.rbegin(), matches.rend()) - 合并重叠/相邻区间:
if (next.start - 预分配结果串:
result.reserve(text.size() + 2 * matches.size()) - 从右往左切片拼接:
result = text.substr(right_end) + replacement + result,避免索引漂移
最关键的细节:别信“字符数 = 掩码星号数”,"宝" 是 3 字节,就得填 3 个 '*',用 std::string(len_byte, '*'),不是硬写 "***" —— 后者在混合中英文场景下必错。

















