• DFA 算法选型思路


    1. 写在最前面

    真的是心力交瘁的一个月,最近在做「敏感词过滤」的功能:

    • 需要识别敏感的英语单词
    • 需要识别敏感的英语词组

    虽然笔者在需求评审会议上极力说明,这个需求的复杂程度比较高,自己实现有种种风险,但是无奈人家人多,被产品和负责人怼回来了。

    行吧,做就做呗。不过这让我想起来一句话,「人有多大胆,地有多大产」。

    2. 算法调研

    2.1 google 大法好

    本着不懂就查的思路,笔者从 google 处得到了一丝丝思路:

    在这里插入图片描述

    2.2 github 一下

    接着这个思路,笔者从一众开源算法中,挑选到了

    注:其实还尝试了 godlp,但这个更倾向于一个根据一系列规则对敏感数据的识别和处置方案,不大适用本场景。

    3. 上手

    3.1 不如试试

    本着 「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()
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    注:./filter-en.txt 为与 mian.go 同级的一个文件,包含「fuck」 字符

    ​ ./filter-cn.txt 为与 main.go 同级的一个文件,包含 「王八」 字符

    3.2 求甚解

    上述两个库都是 DFA 算法的一种实现,实现的时候使用 Trie Tree 这种数据结构。这篇文章主要介绍选项的思路,后续有空会整理一篇 DFA 跟 Trie Tree 相关的文章。

    注:先记在这里,求不打自己的脸。

    4. 遇到的问题

    「出来混,总是会遇到各种各样的问题」

    4.1 英文词组可拆为字母

    英文单词由单词组成,假设敏感词的词库里有 fuck 这个单词,所有带有 fuck 的词组,下图两个 golang 库测试例子:

    在这里插入图片描述

    4.2 误识别的问题

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

    注:做人啊,不能要求太高,连情绪啥的都开源了,人家做这个的公司不得黄了

    5. 碎碎念

    以上就是这个月糟心的开始,毕竟猜测没准产品他们后面就想着要不自己实现一个好了……,但是做人还是要乐观、坚持、努力吖:

    • 相逢的意义在于照亮彼此,不然的话 一个人喝茶也很浪漫,一个人吹风也能清醒。
    • 为什么要蜷缩在黑暗里,仅有一次的人生当然要活的炽热。
    • 在你的成长过程中,你会渐渐发现世界是以这样一种方式在运转着,人们会告诉你世事险恶,你要遵规守纪,不要做一些太出格的事。这是非常局限的生活。当你发现这样一个简单的事实,生命会无限扩展——你身边一切被你称之为生活的事物,都是一些不如你聪慧的人创造的。而你可以影响它们,你可以改变这一切,你可以建造出给别人带来福祉的事物,上面有着只属于你的印记。一旦你学会这一点,你将卓越不凡。

    6. 参考资料

  • 相关阅读:
    028-从零搭建微服务-搜索服务(二)
    List分页
    NIO-Socket实现简易聊天室
    三、程序员指南:数据平面开发套件
    将nginx设置为开启自启动的配置
    2021年初行政区划数据
    阿里云 —— Windows下“阿里云音视频通信RTC“ 之 云端录制编译C++的SDK接口
    oraenv Oracle_SID for sid in
    策略模式(Strategy mode)
    Linux安装和配置C++环境—笔记1
  • 原文地址:https://blog.csdn.net/phantom_111/article/details/126273243