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 Web框架Flask信号机制(signals)介绍
Jan 01 Python
Python字符和字符值(ASCII或Unicode码值)转换方法
May 21 Python
Python 网页解析HTMLParse的实例详解
Aug 10 Python
在python3环境下的Django中使用MySQL数据库的实例
Aug 29 Python
Python序列化基础知识(json/pickle)
Oct 19 Python
Python实现的绘制三维双螺旋线图形功能示例
Jun 23 Python
python+pandas+时间、日期以及时间序列处理方法
Jul 10 Python
对python实现合并两个排序链表的方法详解
Jan 23 Python
Python使用xpath实现图片爬取
Sep 16 Python
python使用requests库爬取拉勾网招聘信息的实现
Nov 20 Python
python实现MD5进行文件去重的示例代码
Jul 09 Python
Python帮你解决手机qq微信内存占用太多问题
Feb 15 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
php中$this-&amp;gt;含义分析
2009/11/29 PHP
学习php笔记 字符串处理
2010/10/19 PHP
php数组函数序列之krsort()- 对数组的元素键名进行降序排序,保持索引关系
2011/11/02 PHP
php环境无法上传文件的解决方法
2014/04/30 PHP
laravel 4安装及入门图文教程
2014/10/29 PHP
yii2框架中使用下拉菜单的自动搜索yii-widget-select2实例分析
2016/01/09 PHP
jQuery中多个元素的Hover事件解决方案
2014/06/12 Javascript
JavaScript实现动态删除列表框值的方法
2015/08/12 Javascript
jQuery实现的漂亮表单效果代码
2015/08/18 Javascript
jQuery Timelinr实现垂直水平时间轴插件(附源码下载)
2016/02/16 Javascript
jQuery插件ajaxfileupload.js实现上传文件
2020/10/23 Javascript
fckeditor部署到weblogic出现xml无法读取及样式不能显示问题的解决方法
2017/03/24 Javascript
AngularJs 延时器、计时器实例代码
2017/09/16 Javascript
微信小程序实现团购或秒杀批量倒计时
2020/11/01 Javascript
浅谈微信小程序flex布局基础
2018/09/10 Javascript
详解React项目如何修改打包地址(编译输出文件地址)
2019/03/21 Javascript
微信小程序移动拖拽视图-movable-view实例详解
2019/08/17 Javascript
layui表格 列自动适应大小失效的解决方法
2019/09/06 Javascript
Vue修改项目启动端口号方法
2019/11/07 Javascript
jQuery实现王者荣耀手风琴效果
2020/01/17 jQuery
Vue3为什么这么快
2020/09/23 Javascript
python 画图 图例自由定义方式
2020/04/17 Python
python中可以声明变量类型吗
2020/06/18 Python
使用JS+CSS3技术:让你的名字动起来
2013/04/27 HTML / CSS
前后端结合实现amazeUI分页效果
2020/08/21 HTML / CSS
白宫黑市官网:White House Black Market
2016/11/17 全球购物
Skyscanner英国:苏格兰的全球三大领先航班搜索服务之一
2017/11/09 全球购物
TripAdvisor日本:全球领先的旅游网站
2019/02/14 全球购物
聚网科技C++面试笔试题
2015/09/01 面试题
ruby如何进行集成操作?Ruby能进行多重继承吗?
2013/10/16 面试题
十一国庆节“向国旗敬礼”主题班会活动方案
2014/09/27 职场文书
班干部学习委员竞选稿
2015/11/20 职场文书
保险公司2016开门红口号集锦
2015/12/24 职场文书
情况说明书格式及范文
2019/06/24 职场文书
Mysql基础之常见函数
2021/04/22 MySQL
Tomcat 与 maven 的安装与使用教程
2022/06/16 Servers