敏感词检测-DFA算法笔记及实现

引子

  敏感词检测,这个是很多文字类服务都要遇到的问题,最近项目上接触到,特此调研梳理下这部分的内容。比如当我们输入一些包含暴力或者色情的文本,系统会阻止信息提交。敏感词过滤就是检查用户输入的内容有没有敏感词。OK,让我们开始吧。

一、算法原理简介

  一般敏感词检测之后有两个处理策略。(1)直接阻止信息保存,接口返回错误信息(2)允许信息保存,但是会把敏感词替换为***。不管是哪种策略,首先都得找到是否包含敏感词,这个判断一般是在服务端完成的。要判断用户输入有无敏感词,就需要有个敏感词库。例如,现在敏感词库中有两个敏感词:“abcd”和“cdef”。最容易想到的方法是遍历敏感词库,依次判断输入内容是否有“abcd”和“cdef”。这种方法是可靠的,但是真实的敏感词库里存放的敏感词是非常多的,如果遍历敏感词库的性能较低,而且大部分情况下用户输入的内容都是不包含敏感词的,大部分情况下遇到的都是算法计算量大的情况,那么就需要找到一种高效的敏感词检测方法。经过调研,发现DFA算法可以做到。

        DFA全称为:Deterministic Finite Automaton,即确定有穷自动机。其特征为:有一个有限状态集合和一些从一个状态通向另一个状态的边,每条边上标记有一个符号,其中一个状态是初态,某些状态是终态。但不同于不确定的有限自动机,DFA中不会有从同一状态出发的两条边标志有相同的符号。敏感词过滤很适合用DFA算法,用户每次输入都是状态的切换,如果出现敏感词,即是终态,就可以结束判断。我们把数组形式的敏感词整理为一个树状结构,准确的说是一个森林。

  这样,就把查找敏感词就变成了一个查找路径的问题,如果用户输入的内容中包含一个从根节点到叶子节点的完整路径,就说明包含敏感词。算法实现逻辑是循环用户输入的字符串,依次查找每个字符是否出现在树的节点上,比如用户输入“打倒日本人”,从第一个字开始判断,“打”不在树的根节点上,进入下一步,“倒”也不在根节点上,进入下一步,“日”出现在了根节点上,这时状态切换,下一步的查找范围变为“日”的子节点;“本”出现在子节点中,状态再次切换为“本”的子节点,“人”出现在子节点中,并且为叶子节点,所以包含敏感词。

二、部分代码

class SensitiveWords():
    def __init__(self, model_file,resp_json):
        with open(model_file,'rb') as f:
            self.keywords = [x.decode('utf8').strip() for x in f.readlines()]
        # print("self.keywords=", self.keywords)
        self.dfa =  DFA(self.keywords)

    def __call__(self, message):
        text = message["datas"][0]
        # print("message=", message)
        res = []
        for start_index, end_index in self.dfa.search(text):
            res.append([start_index, end_index])
        return res

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

要养家的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值