真的是心力交瘁的一个月,最近在做「敏感词过滤」的功能:
虽然笔者在需求评审会议上极力说明,这个需求的复杂程度比较高,自己实现有种种风险,但是无奈人家人多,被产品和负责人怼回来了。
行吧,做就做呗。不过这让我想起来一句话,「人有多大胆,地有多大产」。
本着不懂就查的思路,笔者从 google 处得到了一丝丝思路:

接着这个思路,笔者从一众开源算法中,挑选到了
注:其实还尝试了 godlp,但这个更倾向于一个根据一系列规则对敏感数据的识别和处置方案,不大适用本场景。
本着 「talk is cheap show me the code」的原则,笔者就这两个库,是否能够满足,产品的需求做了一个简单的 POC 尝试,代码如下:
package main
import (
"bytes"
"fmt"
"io/ioutil"
filter "github.com/antlinker/go-dirtyfilter"
"github.com/importcjj/sensitive"
)
func FilterDirtyFilter(path, content string, isReplace bool) ([]string, error) {
fd, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
df := filter.NewNodeReaderFilter(bytes.NewReader(fd), '\n')
var (
result = make([]string, 0)
rs string
)
if isReplace {
rs, err = df.Replace(content, '*')
result = append(result, rs)
} else {
result, err = df.Filter(content)
}
if err != nil {
return nil, err
}
return result, nil
}
func FilterSensitive(path, content string, isReplace bool) ([]string, error) {
filter := sensitive.New()
err := filter.LoadWordDict(path)
if err != nil {
return nil, err
}
if isReplace {
s := filter.Replace(content, '*')
return []string{s}, nil
}
s := filter.FindAll(content)
return s, nil
}
func TestCNFilter() {
c := "小明抓到了一只王八"
fmt.Printf("原始词 %s - 脏词 %s\n", c, "王八")
sr, err := FilterSensitive("./filter-cn.txt", c, true)
if err != nil {
panic(err)
}
dr, err := FilterDirtyFilter("./filter-cn.txt", c, true)
if err != nil {
panic(err)
}
fmt.Println("sensitive", sr)
fmt.Println("dirty", dr)
}
func TestENFilter() {
c := "fucked"
fmt.Printf("原始词 %s - 脏词 %s\n", c, "fuck")
sr, err := FilterSensitive("./filter-en.txt", c, true)
if err != nil {
panic(err)
}
dr, err := FilterDirtyFilter("./filter-en.txt", c, true)
if err != nil {
panic(err)
}
fmt.Println("sensitive", sr)
fmt.Println("dirty", dr)
}
func main() {
TestCNFilter()
fmt.Println()
TestENFilter()
}
注:./filter-en.txt 为与 mian.go 同级的一个文件,包含「fuck」 字符
./filter-cn.txt 为与 main.go 同级的一个文件,包含 「王八」 字符
上述两个库都是 DFA 算法的一种实现,实现的时候使用 Trie Tree 这种数据结构。这篇文章主要介绍选项的思路,后续有空会整理一篇 DFA 跟 Trie Tree 相关的文章。
注:先记在这里,求不打自己的脸。
「出来混,总是会遇到各种各样的问题」
英文单词由单词组成,假设敏感词的词库里有 fuck 这个单词,所有带有 fuck 的词组,下图两个 golang 库测试例子:

开源版本的算法,都是识别部分,不支持对上下文及情绪进行判断,会产生较高的误识别率,下图两个 golang 库测试例子:

注:做人啊,不能要求太高,连情绪啥的都开源了,人家做这个的公司不得黄了
以上就是这个月糟心的开始,毕竟猜测没准产品他们后面就想着要不自己实现一个好了……,但是做人还是要乐观、坚持、努力吖: