在内容平台开发中,敏感词过滤是必不可少的功能。传统的字符串替换方法在面对大量敏感词时性能低下,而本文将介绍如何使用 AC 自动机算法实现一个高性能的敏感词过滤系统。
✨ 核心特性
🚀 高性能算法
- AC 自动机:基于 Aho-Corasick 算法,时间复杂度 O(n)
- 一次扫描:单次遍历即可检测所有敏感词
- 内存优化:使用 Trie 树结构,空间效率高
🎯 智能检测
- 词边界检测:避免"草莓"被"草"误判的问题
- 正则表达式支持:灵活处理手机号、邮箱等模式
- 中英文混合:支持中文、英文、数字的边界判断
🔒 并发安全
- 读写锁:支持多协程并发访问
- 线程安全:生产环境可靠运行
🏗️ 系统架构
核心组件
Go
type SensitiveFilter struct {
matcher *cedar.Matcher // AC自动机匹配器
regexRules map[string]string // 正则规则映射
mu sync.RWMutex // 读写锁
}
工作流程
- 初始化阶段:从文件加载敏感词,构建 AC 自动机
- 检测阶段:使用 AC 自动机快速匹配 + 正则规则补充
- 过滤阶段:替换敏感词并保证不重复处理
💡 核心实现
1. AC 自动机构建
Go
func NewSensitiveFilter() *SensitiveFilter {
words := loadWordsFromFile()
regexRules := loadRegexRules()
// 构建AC自动机
m := cedar.NewMatcher()
for i, word := range words {
m.Insert([]byte(word), i)
}
m.Compile() // 编译自动机
return &SensitiveFilter{
matcher: m,
regexRules: regexRules,
}
}
2. 智能词边界检测
Go
func (f *SensitiveFilter) isWordBoundary(text, word string) bool {
index := strings.Index(text, word)
if index == -1 {
return false
}
// 检查前边界
if index > 0 {
prevChar := rune(text[index-1])
if f.isWordChar(prevChar) {
return false
}
}
// 检查后边界
endIndex := index + len(word)
if endIndex > len(text) {
nextChar := rune(text[endIndex])
if f.isWordChar(nextChar) {
return false
}
}
return true
}
3. 高效过滤算法
Go
func (f *SensitiveFilter) Filter(text string) string {
f.mu.RLock()
defer f.mu.RUnlock()
seq := []byte(text)
resp := f.matcher.Match(seq)
defer resp.Release()
replaced := make(map[string]struct{})
for resp.HasNext() {
items := resp.NextMatchItem(seq)
for _, itr := range items {
wordBytes := f.matcher.Key(seq, itr)
word := string(wordBytes)
if _, exists := replaced[word]; !exists {
text = strings.ReplaceAll(text, word, "########")
replaced[word] = struct{}{}
}
}
}
// 正则规则补充
for pattern, replacement := range f.regexRules {
re := regexp.MustCompile(pattern)
text = re.ReplaceAllString(text, replacement)
}
return text
}
📊 性能优势
算法复杂度对比
| 方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 暴力匹配 | O(n×m×k) | O(1) | 敏感词少 |
| KMP算法 | O(n×k) | O(m) | 单词匹配 |
| AC自动机 | O(n) | O(m×k) | 多词匹配 |
🛡️ 安全特性
1. 正则规则扩展
Go
regexRules := map[string]string{
`\d{11}`: "[手机号]", // 手机号脱敏
`(?i)test`: "***", // 不区分大小写
}
2. 并发安全保障
Go
func (f *SensitiveFilter) Check(text string) bool {
f.mu.RLock()
defer f.mu.RUnlock()
// 安全的并发检测
}
🚀 使用示例
基础用法
Go
// 初始化过滤器
filter := sensitive_ser.NewSensitiveFilter()
// 检测敏感词
hasSensitive := filter.Check("这是一段测试文本")
// 过滤敏感词
cleanText := filter.Filter("这是一段包含敏感词的文本")
集成到业务系统
Go
// 在聊天系统中使用
func HandleMessage(info ClientInfo, content string) {
// 过滤敏感词
filterContent := global.SensitiveFilter.Filter(content)
// 广播清洁内容
Broadcast(filterContent)
}