敏感词过滤必须用[]rune而非[]byte,因中文、emoji等utf-8多字节字符被[]byte遍历会截断导致匹配失效;isend须在完整匹配后赋值,避免误杀;需支持重叠匹配与nil map安全访问。

敏感词过滤必须用 []rune,别碰 []byte
中文、emoji、生僻字在 Go 里不是“一个字一个字节”,[]byte 遍历会切开 UTF-8 编码,导致“王八蛋”被拆成 '王'(3 字节)、'八'(3 字节)中间插乱码,匹配直接失效。
- 所有敏感词插入前、文本扫描前,统一转成
[]rune:chars := []rune(text) -
for i := range word是错的——它遍历的是字节索引;必须用for _, r := range word或for i, r := range []rune(word) - 如果硬要优化 ASCII 日志场景(纯英文数字),得先加校验:
utf8.ValidString(text),否则线上一跑中文就漏词
isEnd = true 放错位置,误杀率直接拉满
“王八蛋”进树时,如果在“王”节点、或“王八”节点就设 isEnd = true,那只要出现“王”字,哪怕后面跟的是“老师”,也会被当成敏感词拦截。
- 正确做法:循环完所有
rune后,在最终节点才赋值node.isEnd = true - 错误写法示例(常见于复制粘贴的 demo):
for _, r := range word {<br> node = node.getChild(r)<br> node.isEnd = true // ❌ 错!每走一步都标结尾<br>} - 如需支持“前缀敏感”(“王八”和“王八蛋”都算),必须新增字段如
isPrefix bool,不能复用isEnd
匹配时只返回第一个词?那是没实现「重叠匹配」
输入 "王八羔子",只命中 "王八" 就停,漏掉更长的 "王八羔子"——这是 DFA 实现最典型的逻辑断点。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 关键不是“找最长”,而是“每个起点都要试”:从索引 0 开始匹配,命中后记录;再从索引 1 重新进树,继续找
- 简单可靠的做法是双指针:
start固定,end推进,找到isEnd就记下范围,然后start++继续 - 别用
strings.ReplaceAllFunc做生产环境过滤——它内部是单次扫描,不支持重叠,且性能差一个数量级
node.Next[c] panic?90% 没判 nil
本地小数据测不出,压测时突然 panic: assignment to entry in nil map,堆栈指向 AddChild 或匹配循环里的 node.children[char]——这就是没检查 map 是否初始化。
- 每次访问或写入
node.Next前,必须确认:if node.Next == nil { node.Next = make(map[rune]*Node) } - 更稳妥的是封装方法:
func (n *Node) getChild(r rune) *Node和func (n *Node) setChild(r rune, child *Node),内部统一判空 - 别信“我建树时肯定初始化了”——并发加载、热更新、配置变更都可能让某分支的
Next仍是nil
真正难的不是写对一棵树,而是让这棵树在高并发、多字节、热更新、误匹配压力下不崩、不漏、不误杀。每一个 range 写法、每一处 nil 判定、每一次 isEnd 赋值位置,都在决定它上线后是默默扛住流量,还是凌晨三点弹出告警。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










