實現高性能敏感詞過濾:給定敏感詞庫,對輸入文本進行檢測並替換 (如用 * 遮罩)。要求支持中英文混合、大小寫不敏感、高併發。
每個節點存儲:
map 或數組 Node* next[CHARS]bool isEndstruct TrieNode {
unordered_map children;
bool isEnd = false;
TrieNode() {}
~TrieNode() {
for (auto& p : children) delete p.second;
}
};
class SensitiveFilter {
TrieNode* root;
public:
SensitiveFilter() : root(new TrieNode()) {}
~SensitiveFilter() { delete root; }
void addWord(const string& word) {
TrieNode* p = root;
for (char c : word) {
if (!p->children.count(c)) p->children[c] = new TrieNode();
p = p->children[c];
}
p->isEnd = true;
}
// 簡單過濾:逐字符匹配,命中則替換
string filter(const string& text) {
string result;
for (size_t i = 0; i < text.size(); ) {
TrieNode* p = root;
size_t j = i;
int lastEnd = -1;
while (j < text.size() && p->children.count(text[j])) {
p = p->children[text[j]];
if (p->isEnd) lastEnd = j;
++j;
}
if (lastEnd != -1) {
result.append(lastEnd - i + 1, '*');
i = lastEnd + 1;
} else {
result.push_back(text[i]);
++i;
}
}
return result;
}
};
Trie 逐字符匹配最壞 O(n × maxLen)。AC 自動機構建失敗指針,單次掃描文本即可找出所有敏感詞位置。
struct ACNode {
array next{};
ACNode* fail = nullptr;
bool isEnd = false;
int wordLen = 0; // 敏感詞長度,用於替換
ACNode() { next.fill(nullptr); }
};
class ACFilter {
ACNode* root;
public:
ACFilter() : root(new ACNode()) {}
~ACFilter() { deleteTree(root); }
void addWord(const string& word) {
ACNode* p = root;
for (char c : word) {
int idx = tolower(c) - 'a';
if (!p->next[idx]) p->next[idx] = new ACNode();
p = p->next[idx];
}
p->isEnd = true;
p->wordLen = word.length();
}
void buildFail() {
queue q;
root->fail = root;
for (int i = 0; i < 26; ++i) {
if (root->next[i]) {
root->next[i]->fail = root;
q.push(root->next[i]);
} else {
root->next[i] = root; // 統一跳轉
}
}
while (!q.empty()) {
ACNode* u = q.front(); q.pop();
for (int i = 0; i < 26; ++i) {
if (u->next[i]) {
u->next[i]->fail = u->fail->next[i];
u->next[i]->isEnd |= u->next[i]->fail->isEnd; // 合併輸出
q.push(u->next[i]);
} else {
u->next[i] = u->fail->next[i];
}
}
}
}
string filter(const string& text) {
string result = text;
ACNode* p = root;
for (size_t i = 0; i < text.size(); ++i) {
int idx = tolower(text[i]) - 'a';
if (idx < 0 || idx >= 26) { p = root; continue; }
p = p->next[idx];
if (p->isEnd) {
// 替換結尾為 i,長度 p->wordLen
for (int k = 0; k < p->wordLen; ++k)
result[i - k] = '*';
}
}
return result;
}
};
中文字符佔 3 字節 (UTF-8)。選項:
unsigned char 作為邊,節點數增加但實現簡單char32_t 或 uint32_t,邊數大需用 unordered_mapstruct ByteTrieNode {
array next{};
bool isEnd = false;
ByteTrieNode() { next.fill(nullptr); }
};
// 插入時直接按字節遍歷
void addWordBytes(ByteTrieNode* root, const string& word) {
ByteTrieNode* p = root;
for (unsigned char c : word) {
if (!p->next[c]) p->next[c] = new ByteTrieNode();
p = p->next[c];
}
p->isEnd = true;
}
| 優化 | 說明 |
|---|---|
| 內存池 | 預分配節點數組,避免 new/delete 碎片 |
| 雙數組 Trie | 靜態化、極致壓縮、cache 友好,適合靜態詞庫 |
| 分詞預處理 | 結合分詞器 (如 jieba) 針對詞邊界匹配,減少誤殺 |
| 分級過濾 | 一級:關鍵字哈希集合快速篩選;二級:Trie/AC 精確匹配 |
| 並行化 | 文本分塊並行過濾,邊界重疊處理 |
敏感詞過濾是典型的「多模式匹配」問題,Trie/AC 自動機是標準解法。理解其原理與工程化細節,可構建高性能、可維護的內容安全系統。