Python使用DFA算法过滤内容敏感词


Posted in Python onApril 22, 2022

DFA 算法是通过提前构造出一个 树状查找结构,之后根据输入在该树状结构中就可以进行非常高效的查找。

设我们有一个敏感词库,词酷中的词汇为:

  • 我爱你
  • 我爱他
  • 我爱她
  • 我爱你呀
  • 我爱他呀
  • 我爱她呀
  • 我爱她啊

那么就可以构造出这样的树状结构:

设玩家输入的字符串为:白菊我爱你呀哈哈哈

我们遍历玩家输入的字符串 str,并设指针 i 指向树状结构的根节点,即最左边的空白节点:

  • str[0] = ‘白’ 时,此时 tree[i] 没有指向值为 ‘白’ 的节点,所以不满足匹配条件,继续往下遍历
  • str[1] = ‘菊’,同样不满足匹配条件,继续遍历
  • str[2] = ‘我’,此时 tree[i] 有一条路径连接着 ‘我’ 这个节点,满足匹配条件,i 指向 ‘我’ 这个节点,然后继续遍历
  • str[3] = ‘爱’,此时 tree[i] 有一条路径连着 ‘爱’ 这个节点,满足匹配条件,i 指向 ‘爱’,继续遍历
  • str[4] = ‘你’,同样有路径,i 指向 ‘你’,继续遍历
  • str[5] = ‘呀’,同样有路径,i 指向 ‘呀’

此时,我们的指针 i 已经指向了树状结构的末尾,即此时已经完成了一次敏感词判断。我们可以用变量来记录下这次敏感词匹配开始时玩家输入字符串的下标,和匹配结束时的下标,然后再遍历一次将字符替换为 * 即可。

结束一次匹配后,我们把指针 i 重新指向树状结构的根节点处。

此时我们玩家输入的字符串还没有遍历到头,所以继续遍历:

str[6] = ‘哈’,不满足匹配条件,继续遍历

str[7] = ‘哈’ …

str[8] = ‘哈’ …

可以看出我们遍历了一次玩家输入的字符串,就找到了其中的敏感词汇。

Python使用DFA算法过滤内容敏感词

DFA算法python实现

class DFA:
    """DFA 算法
       敏感字中“*”代表任意一个字符
    """

    def __init__(self, sensitive_words: list, skip_words: list):  # 对于敏感词sensitive_words及无意义的词skip_words可以通过数据库、文件或者其他存储介质进行保存
        self.state_event_dict = self._generate_state_event(sensitive_words)
        self.skip_words = skip_words

    def __repr__(self):
        return '{}'.format(self.state_event_dict)

    @staticmethod
    def _generate_state_event(sensitive_words) -> dict:
        state_event_dict = {}
        for word in sensitive_words:
            tmp_dict = state_event_dict
            length = len(word)
            for index, char in enumerate(word):
                if char not in tmp_dict:
                    next_dict = {'is_end': False}
                    tmp_dict[char] = next_dict
                    tmp_dict = next_dict
                else:
                    next_dict = tmp_dict[char]
                    tmp_dict = next_dict
                if index == length - 1:
                    tmp_dict['is_end'] = True
        return state_event_dict

    def match(self, content: str):
        match_list = []
        state_list = []
        temp_match_list = []

        for char_pos, char in enumerate(content):
            if char in self.skip_words:
                continue
            if char in self.state_event_dict:
                state_list.append(self.state_event_dict)
                temp_match_list.append({
                    "start": char_pos,
                    "match": ""
                })
            for index, state in enumerate(state_list):
                is_match = False
                state_char = None
                if '*' in state: # 对于一些敏感词,比如大傻X,可能是大傻B,大傻×,大傻...,采用通配符*,一个*代表一个字符
                    state_list[index] = state['*']
                    state_char = state['*']
                    is_match = True
                if char in state:
                    state_list[index] = state[char]
                    state_char = state[char]
                    is_match = True
                if is_match:
                    if state_char["is_end"]:
                        stop = char_pos + 1
                        temp_match_list[index]['match'] = content[
                                                          temp_match_list[index]['start']:stop]
                        match_list.append(copy.deepcopy(temp_match_list[index]))
                        if len(state_char.keys()) == 1:
                            state_list.pop(index)
                            temp_match_list.pop(index)
                else:
                    state_list.pop(index)
                    temp_match_list.pop(index)
        for index, match_words in enumerate(match_list):
            print(match_words['start'])
        return match_list

_generate_state_event方法生成敏感词的树状结构,(以字典保存),对于上面的例子,生成的树状结构保存如下:

if __name__ == '__main__':
    dfa = DFA(['我爱你', '我爱他', '我爱她', '我爱你呀', '我爱他呀', '我爱她呀', '我爱她啊'], skip_words=[])  # 暂时不配置skip_words
    print(dfa)

结果:

{'我': {'is_end': False, '爱': {'is_end': False, '你': {'is_end': True, '呀': {'is_end': True}}, '他': {'is_end': True, '呀': {'is_end': True}}, '她': {'is_end': True, '呀': {'is_end': True}, '啊': {'is_end': True}}}}}

然后调用match方法,输入内容进行敏感词匹配:

if __name__ == '__main__':
    dfa = DFA(['我爱你', '我爱他', '我爱她', '我爱你呀', '我爱他呀', '我爱她呀', '我爱她啊'], ['\n', '\r\n', '\r'])
    # print(dfa)
    print(dfa.match('白菊我爱你呀哈哈哈'))

结果:

[{'start': 2, 'match': '我爱你'}, {'start': 2, 'match': '我爱你呀'}]

而对于一些敏感词,比如大傻X,可能是大傻B,大傻×,大傻...,那是不是可以通过一个通配符*来解决?

见代码:48 ~51行

if '*' in state: # 对于一些敏感词,比如大傻X,可能是大傻B,大傻×,大傻...,采用通配符*,一个*代表一个字符
 state_list[index] = state['*']
 state_char = state['*']
 is_match = True

验证一下:

if __name__ == '__main__':
    dfa = DFA(['大傻*'], [])
    print(dfa)
    print(dfa.match('大傻X安乐飞大傻B'))

{'大': {'is_end': False, '傻': {'is_end': False, '*': {'is_end': True}}}}
[{'start': 0, 'match': '大傻X'}, {'start': 6, 'match': '大傻B'}]

上列中如果输入的内容中,“大傻X安乐飞大傻B”写成“大%傻X安乐飞大&傻B”,看看是否能识别出敏感词呢?识别不出了!

if __name__ == '__main__':
    dfa = DFA(['大傻*'], [])
    print(dfa)
    print(dfa.match('大%傻X安乐飞大&傻B'))

结果:

{'大': {'is_end': False, '傻': {'is_end': False, '*': {'is_end': True}}}}
[

诸如“,&,!,!,@,#,$,¥,*,^,%,?,?,<,>,《,》",这些特殊符号无实际意义,但是可以在敏感词中间插入而破坏敏感词的结构规避敏感词检查

进行无意义词配置,再进行敏感词检查,如下,可见对于被破坏的敏感词也能识别

if __name__ == '__main__':
    dfa = DFA(['大傻*'], ['%', '&'])
    print(dfa)
    print(dfa.match('大%傻X安乐飞大&傻B'))

结果: 

{'大': {'is_end': False, '傻': {'is_end': False, '*': {'is_end': True}}}}
[{'start': 0, 'match': '大%傻X'}, {'start': 7, 'match': '大&傻B'}]

以上就是Python基于DFA算法实现内容敏感词过滤的详细内容!


Tags in this post...

Python 相关文章推荐
Python 第一步 hello world
Sep 25 Python
跟老齐学Python之让人欢喜让人忧的迭代
Oct 02 Python
Python中将字典转换为XML以及相关的命名空间解析
Oct 15 Python
Python中正则表达式详解
May 17 Python
Python中super函数用法实例分析
Mar 18 Python
python之pyqt5通过按钮改变Label的背景颜色方法
Jun 13 Python
Python实现网页截图(PyQT5)过程解析
Aug 12 Python
Python 装饰器@,对函数进行功能扩展操作示例【开闭原则】
Oct 17 Python
使用Pandas的Series方法绘制图像教程
Dec 04 Python
Python列表操作方法详解
Feb 09 Python
Python with语句用法原理详解
Jul 03 Python
Python全局变量与global关键字常见错误解决方案
Oct 05 Python
python游戏开发之pygame实现接球小游戏
Apr 22 #Python
python游戏开发Pygame框架
Apr 22 #Python
python中的random模块和相关函数详解
Apr 22 #Python
Python写情书? 10行代码展示如何把情书写在她的照片里
Apr 21 #Python
微信小程序调用python模型
Apr 21 #Python
使用python绘制分组对比柱状图
使用python将HTML转换为PDF pdfkit包(wkhtmltopdf) 的使用方法
Apr 21 #Python
You might like
3
2006/10/09 PHP
如何用PHP来实现一个动态Web服务器
2015/07/29 PHP
PHP 7.0新增加的特性介绍
2017/06/08 PHP
jQueryPad 实用的jQuery测试工具(支持IE,chrome,FF)
2010/05/22 Javascript
jquery原创弹出层折叠效果点击折叠弹出一个层
2014/03/12 Javascript
javascript上下方向键控制表格行选中并高亮显示的方法
2015/02/13 Javascript
JavaScript使用二分查找算法在数组中查找数据的方法
2015/04/07 Javascript
Jquery实现的简单轮播效果【附实例】
2016/04/19 Javascript
jquery之别踩白块游戏的简单实现
2016/07/25 Javascript
vue-router路由简单案例介绍
2017/02/21 Javascript
jQuery阻止移动端遮罩层后页面滚动
2017/03/15 Javascript
js实现数字递增特效【仿支付宝我的财富】
2017/05/05 Javascript
几种响应式文字详解
2017/05/19 Javascript
基于jQuery封装的分页组件
2017/06/26 jQuery
详解vue的diff算法原理
2018/05/20 Javascript
一个因@click.stop引发的bug的解决
2019/01/08 Javascript
JS实现的检验身份证格式并输出出生日期,年龄,性别,出生地示例
2019/05/17 Javascript
教你完全理解ReentrantLock重入锁
2019/06/03 Javascript
微信小程序实现左侧滑动导航栏
2020/04/08 Javascript
vue-父子组件和ref实例详解
2019/11/10 Javascript
基于JavaScript实现轮播图效果
2021/01/02 Javascript
[51:29]Alliance vs TNC 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/18 DOTA
浅谈dataframe中更改列属性的方法
2018/07/10 Python
pandas 将索引值相加的方法
2018/11/15 Python
Python3使用腾讯云文字识别(腾讯OCR)提取图片中的文字内容实例详解
2020/02/18 Python
关于Python不换行输出和不换行输出end=““不显示的问题(亲测已解决)
2020/10/27 Python
HTML5进阶段内联标签汇总(小篇)
2016/07/13 HTML / CSS
三只松鼠官方旗舰店:全网坚果销售第1
2017/11/25 全球购物
公关关系专员的自我评价分享
2013/11/20 职场文书
销售实习自我鉴定
2013/12/07 职场文书
护理专科毕业自荐信范文
2014/04/21 职场文书
中学生自我评价范文
2015/03/03 职场文书
毕业班班主任工作总结2015
2015/07/23 职场文书
Python实现文本文件拆分写入到多个文本文件的方法
2021/04/18 Python
CSS精灵图的原理与使用方法介绍
2022/03/17 HTML / CSS
一篇文章带你掌握SQLite3基本用法
2022/06/14 数据库