最直接的敏感词过滤是替换为空字符串;需用std::string::find手动扫描以处理重叠匹配,敏感词应按长度降序排列,并注意utf-8编码、正则转义、大小写及性能优化。

敏感词替换为空字符串是最直接的做法
多数场景下,你不需要“删除”这个词的语义逻辑,而是把匹配到的敏感词替换成空字符串 ""。C++ 标准库没有内置的多模式敏感词过滤器,所以得靠 std::string::find + std::string::replace 或正则 std::regex_replace 实现。但要注意:简单循环替换可能漏掉重叠匹配(比如敏感词是 "ab" 和 "abc",原串是 "abc"),而正则默认不支持全局非重叠匹配控制。
推荐先用 std::string::find 手动扫描:
std::string filter_sensitive(std::string text, const std::vector<:string>& words) {
for (const auto& word : words) {
size_t pos = 0;
while ((pos = text.find(word, pos)) != std::string::npos) {
text.replace(pos, word.length(), "");
// 不加 pos += 1,否则跳过可能的重叠(如 "aaa" 中删 "aa")
// 但也不宜直接 pos += word.length(),会漏掉前缀重叠
pos += 1; // 小步前进,覆盖重叠情况(代价是性能略降)
}
}
return text;
}</:string>
用 std::regex 要小心转义和性能
如果敏感词含特殊字符(.、*、[ 等),直接传给 std::regex 会出错——它们会被当作正则元字符解析。必须先 escape,C++ 没有内置 escape 函数,得自己写:
-
std::regex构造失败时抛std::regex_error,务必 try-catch - 每个敏感词单独编译 regex 比拼成一个
(word1|word2|...)更安全(避免括号/竖线冲突) - 大量敏感词 + 频繁调用时,
std::regex编译开销明显,建议缓存std::regex对象
简单 escape 示例(只处理基本元字符):
std::string escape_regex(const std::string& s) {
static const std::string meta = R"(.^$|[]*+?{}())";
std::string out;
for (char c : s) {
if (meta.find(c) != std::string::npos) out += '\';
out += c;
}
return out;
}
多个敏感词顺序会影响结果
敏感词列表顺序不是无关紧要的。例如,若列表是 {"ab", "abc"},对输入 "abc" 先删 "ab" 得 "c",再找不到 "abc";反过来,先删 "abc" 得空串。这不是 bug,而是策略选择。
常见做法:
- 按长度降序排列(长词优先),减少被短词“截断”的可能
- 若业务要求“最长匹配优先”,就得用 Aho-Corasick 等算法,标准库不提供
- 避免在同一个位置反复增删——比如
"ass"和"s"同时存在,可能产生多次替换抖动
生产环境别忽略编码和边界场景
中文敏感词通常为 UTF-8 编码,而 std::string 是字节序列,find 按字节匹配。如果敏感词含多字节字符(如 "违规"),只要源文本和敏感词都用 UTF-8 且未被截断,find 仍可工作;但切忌用 substr 按字符数截取——那会破坏 UTF-8 编码。
其他易忽略点:
- 大小写问题:
"Apple"和"apple"是否等价?需统一转小写再比,但注意 locale(std::tolower需配std::locale) - 空格和标点干扰:用户可能输入
"违 规"或"违 规",基础方案无法处理,得预处理或改用分词式匹配 - 性能敏感场景(如每秒千次过滤),应避免每次构造 vector、反复 find,考虑预编译 trie 或使用第三方库如
hyperscan
最简健壮起点:确定敏感词集固定、无重叠歧义、输入可控,就用带长度排序 + 字节级 find/replace;一旦出现模糊匹配、上下文判断或吞吐压力,就得换方案了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











