Python实现敏感词过滤的4种方法


Posted in Python onSeptember 12, 2020

在我们生活中的一些场合经常会有一些不该出现的敏感词,我们通常会使用*去屏蔽它,例如:尼玛 -> **,一些骂人的敏感词和一些政治敏感词都不应该出现在一些公共场合中,这个时候我们就需要一定的手段去屏蔽这些敏感词。下面我来介绍一些简单版本的敏感词屏蔽的方法。

(我已经尽量把脏话做成图片的形式了,要不然文章发不出去)

方法一:replace过滤

replace就是最简单的字符串替换,当一串字符串中有可能会出现的敏感词时,我们直接使用相应的replace方法用*替换出敏感词即可。

缺点:

文本和敏感词少的时候还可以,多的时候效率就比较差了

Python实现敏感词过滤的4种方法

import datetime
now = datetime.datetime.now()
print(filter_sentence, " | ", now)

Python实现敏感词过滤的4种方法

如果是多个敏感词可以用列表进行逐一替换

Python实现敏感词过滤的4种方法

for i in dirty:
 speak = speak.replace(i, '*')
print(speak, " | ", now)

Python实现敏感词过滤的4种方法

方法二:正则表达式过滤

正则表达式算是一个不错的匹配方法了,日常的查询中,机会都会用到正则表达式,包括我们的爬虫,也都是经常会使用到正则表达式的,在这里我们主要是使用“|”来进行匹配,“|”的意思是从多个目标字符串中选择一个进行匹配。写个简单的例子:

Python实现敏感词过滤的4种方法

import re

def sentence_filter(keywords, text):
 return re.sub("|".join(keywords), "***", text)

print(sentence_filter(dirty, speak))

Python实现敏感词过滤的4种方法

方法三:DFA过滤算法

DFA的算法,即Deterministic Finite Automaton算法,翻译成中文就是确定有穷自动机算法。它的基本思想是基于状态转移来检索敏感词,只需要扫描一次待检测文本,就能对所有敏感词进行检测。(实现见代码注释)

Python实现敏感词过滤的4种方法

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time:2020/4/15 11:40
# @Software:PyCharm
# article_add: https://www.cnblogs.com/JentZhang/p/12718092.html
__author__ = "JentZhang"
import json

MinMatchType = 1 # 最小匹配规则
MaxMatchType = 2 # 最大匹配规则


class DFAUtils(object):
 """
 DFA算法
 """

 def __init__(self, word_warehouse):
  """
  算法初始化
  :param word_warehouse:词库
  """
  # 词库
  self.root = dict()
  # 无意义词库,在检测中需要跳过的(这种无意义的词最后有个专门的地方维护,保存到数据库或者其他存储介质中)
  self.skip_root = [' ', '&', '!', '!', '@', '#', '$', '¥', '*', '^', '%', '?', '?', '<', '>', "《", '》']
  # 初始化词库
  for word in word_warehouse:
   self.add_word(word)

 def add_word(self, word):
  """
  添加词库
  :param word:
  :return:
  """
  now_node = self.root
  word_count = len(word)
  for i in range(word_count):
   char_str = word[i]
   if char_str in now_node.keys():
    # 如果存在该key,直接赋值,用于下一个循环获取
    now_node = now_node.get(word[i])
    now_node['is_end'] = False
   else:
    # 不存在则构建一个dict
    new_node = dict()

    if i == word_count - 1: # 最后一个
     new_node['is_end'] = True
    else: # 不是最后一个
     new_node['is_end'] = False

    now_node[char_str] = new_node
    now_node = new_node

 def check_match_word(self, txt, begin_index, match_type=MinMatchType):
  """
  检查文字中是否包含匹配的字符
  :param txt:待检测的文本
  :param begin_index: 调用getSensitiveWord时输入的参数,获取词语的上边界index
  :param match_type:匹配规则 1:最小匹配规则,2:最大匹配规则
  :return:如果存在,则返回匹配字符的长度,不存在返回0
  """
  flag = False
  match_flag_length = 0 # 匹配字符的长度
  now_map = self.root
  tmp_flag = 0 # 包括特殊字符的敏感词的长度

  for i in range(begin_index, len(txt)):
   word = txt[i]

   # 检测是否是特殊字符"
   if word in self.skip_root and len(now_map) < 100:
    # len(nowMap)<100 保证已经找到这个词的开头之后出现的特殊字符
    tmp_flag += 1
    continue

   # 获取指定key
   now_map = now_map.get(word)
   if now_map: # 存在,则判断是否为最后一个
    # 找到相应key,匹配标识+1
    match_flag_length += 1
    tmp_flag += 1
    # 如果为最后一个匹配规则,结束循环,返回匹配标识数
    if now_map.get("is_end"):
     # 结束标志位为true
     flag = True
     # 最小规则,直接返回,最大规则还需继续查找
     if match_type == MinMatchType:
      break
   else: # 不存在,直接返回
    break

  if tmp_flag < 2 or not flag: # 长度必须大于等于1,为词
   tmp_flag = 0
  return tmp_flag

 def get_match_word(self, txt, match_type=MinMatchType):
  """
  获取匹配到的词语
  :param txt:待检测的文本
  :param match_type:匹配规则 1:最小匹配规则,2:最大匹配规则
  :return:文字中的相匹配词
  """
  matched_word_list = list()
  for i in range(len(txt)): # 0---11
   length = self.check_match_word(txt, i, match_type)
   if length > 0:
    word = txt[i:i + length]
    matched_word_list.append(word)
    # i = i + length - 1
  return matched_word_list

 def is_contain(self, txt, match_type=MinMatchType):
  """
  判断文字是否包含敏感字符
  :param txt:待检测的文本
  :param match_type:匹配规则 1:最小匹配规则,2:最大匹配规则
  :return:若包含返回true,否则返回false
  """
  flag = False
  for i in range(len(txt)):
   match_flag = self.check_match_word(txt, i, match_type)
   if match_flag > 0:
    flag = True
  return flag

 def replace_match_word(self, txt, replace_char='*', match_type=MinMatchType):
  """
  替换匹配字符
  :param txt:待检测的文本
  :param replace_char:用于替换的字符,匹配的敏感词以字符逐个替换,如"你是大王八",敏感词"王八",替换字符*,替换结果"你是大**"
  :param match_type:匹配规则 1:最小匹配规则,2:最大匹配规则
  :return:替换敏感字字符后的文本
  """
  tuple_set = self.get_match_word(txt, match_type)
  word_set = [i for i in tuple_set]
  result_txt = ""
  if len(word_set) > 0: # 如果检测出了敏感词,则返回替换后的文本
   for word in word_set:
    replace_string = len(word) * replace_char
    txt = txt.replace(word, replace_string)
    result_txt = txt
  else: # 没有检测出敏感词,则返回原文本
   result_txt = txt
  return result_txt


if __name__ == '__main__':
 dfa = DFAUtils(word_warehouse=word_warehouse)
 print('词库结构:', json.dumps(dfa.root, ensure_ascii=False))
 # 待检测的文本
 msg = msg
 print('是否包含:', dfa.is_contain(msg))
 print('相匹配的词:', dfa.get_match_word(msg))
 print('替换包含的词:', dfa.replace_match_word(msg))

Python实现敏感词过滤的4种方法

方法四:AC自动机

AC自动机需要有前置知识:Trie树(简单介绍:又称前缀树,字典树,是用于快速处理字符串的问题,能做到快速查找到一些字符串上的信息。)

详细参考:

python可以利用ahocorasick模块快速实现:

Python实现敏感词过滤的4种方法

# python3 -m pip install pyahocorasick
import ahocorasick

def build_actree(wordlist):
 actree = ahocorasick.Automaton()
 for index, word in enumerate(wordlist):
  actree.add_word(word, (index, word))
 actree.make_automaton()
 return actree

if __name__ == '__main__':
 actree = build_actree(wordlist=wordlist)
 sent_cp = sent
 for i in actree.iter(sent):
  sent_cp = sent_cp.replace(i[1][1], "**")
  print("屏蔽词:",i[1][1])
 print("屏蔽结果:",sent_cp)

Python实现敏感词过滤的4种方法

当然,我们也可以手写一份AC自动机,具体参考:

class TrieNode(object):
 __slots__ = ['value', 'next', 'fail', 'emit']

 def __init__(self, value):
  self.value = value
  self.next = dict()
  self.fail = None
  self.emit = None


class AhoCorasic(object):
 __slots__ = ['_root']

 def __init__(self, words):
  self._root = AhoCorasic._build_trie(words)

 @staticmethod
 def _build_trie(words):
  assert isinstance(words, list) and words
  root = TrieNode('root')
  for word in words:
   node = root
   for c in word:
    if c not in node.next:
     node.next[c] = TrieNode(c)
    node = node.next[c]
   if not node.emit:
    node.emit = {word}
   else:
    node.emit.add(word)
  queue = []
  queue.insert(0, (root, None))
  while len(queue) > 0:
   node_parent = queue.pop()
   curr, parent = node_parent[0], node_parent[1]
   for sub in curr.next.itervalues():
    queue.insert(0, (sub, curr))
   if parent is None:
    continue
   elif parent is root:
    curr.fail = root
   else:
    fail = parent.fail
    while fail and curr.value not in fail.next:
     fail = fail.fail
    if fail:
     curr.fail = fail.next[curr.value]
    else:
     curr.fail = root
  return root

 def search(self, s):
  seq_list = []
  node = self._root
  for i, c in enumerate(s):
   matched = True
   while c not in node.next:
    if not node.fail:
     matched = False
     node = self._root
     break
    node = node.fail
   if not matched:
    continue
   node = node.next[c]
   if node.emit:
    for _ in node.emit:
     from_index = i + 1 - len(_)
     match_info = (from_index, _)
     seq_list.append(match_info)
    node = self._root
  return seq_list


if __name__ == '__main__':
 aho = AhoCorasic(['foo', 'bar'])
 print aho.search('barfoothefoobarman')

以上便是使用Python实现敏感词过滤的四种方法,前面两种方法比较简单,后面两种偏向算法,需要先了解算法具体实现的原理,之后代码就好懂了。(DFA作为比较常用的过滤手段,建议大家掌握一下~)

最后附上敏感词词库:

https://github.com/qloog/sensitive_words

以上就是Python实现敏感词过滤的4种方法的详细内容,更多关于python 敏感词过滤的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
使用Python下的XSLT API进行web开发的简单教程
Apr 15 Python
Python 根据日志级别打印不同颜色的日志的方法示例
Aug 08 Python
Django框架 querySet功能解析
Sep 04 Python
matplotlib.pyplot画图并导出保存的实例
Dec 07 Python
Pandas时间序列重采样(resample)方法中closed、label的作用详解
Dec 10 Python
PHP基于phpqrcode类库生成二维码过程解析
May 28 Python
Python 存取npy格式数据实例
Jul 01 Python
opencv 图像滤波(均值,方框,高斯,中值)
Jul 08 Python
深入了解Python装饰器的高级用法
Aug 13 Python
Pyqt助手安装PyQt5帮助文档过程图解
Nov 20 Python
Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版)
Feb 22 Python
教你怎么用Python操作MySql数据库
May 31 Python
Python CategoricalDtype自定义排序实现原理解析
Sep 11 #Python
python 如何利用argparse解析命令行参数
Sep 11 #Python
Python Pivot table透视表使用方法解析
Sep 11 #Python
Python extract及contains方法代码实例
Sep 11 #Python
python 利用zmail库发送邮件
Sep 11 #Python
浅析Python 责任链设计模式
Sep 11 #Python
详解python命令提示符窗口下如何运行python脚本
Sep 11 #Python
You might like
国产动画《伍六七》原声大碟大卖,啊哈娱乐引领音乐赋能IP的新尝试
2020/03/08 国漫
php中的boolean(布尔)类型详解
2013/10/28 PHP
php定义数组和使用示例(php数组的定义方法)
2014/03/29 PHP
PHP三元运算的2种写法代码实例
2014/05/12 PHP
通过php删除xml文档内容的方法
2015/01/23 PHP
php限制ip地址范围的方法
2015/03/31 PHP
PHP SOCKET编程详解
2015/05/22 PHP
php实现window平台的checkdnsrr函数
2015/05/27 PHP
php自动识别文字编码并转换为目标编码的方法
2015/08/08 PHP
php+ajax实现无刷新分页
2015/11/18 PHP
跟着JQuery API学Jquery 之三 筛选
2010/04/09 Javascript
从QQ网站中提取的纯JS省市区三级联动菜单
2013/12/25 Javascript
JS调用页面表格导出excel示例代码
2014/03/18 Javascript
实例讲解JQuery中this和$(this)区别
2014/12/08 Javascript
jQuery1.9+中删除了live以后的替代方法
2016/06/17 Javascript
AngularJS实现分页显示数据库信息
2016/07/01 Javascript
vue.js+boostrap项目实践(案例详解)
2016/09/21 Javascript
用javascript获取任意颜色的更亮或更暗颜色值示例代码
2017/07/21 Javascript
pace.js和NProgress.js两个加载进度插件的一点小总结
2018/01/31 Javascript
解决select2在bootstrap modal中不能正常使用的问题
2018/08/09 Javascript
selenium + python 获取table数据的示例讲解
2018/10/13 Python
python快速编写单行注释多行注释的方法
2019/07/31 Python
Python在OpenCV里实现极坐标变换功能
2019/09/02 Python
使用OpenCV获取图片连通域数量,并用不同颜色标记函
2020/06/04 Python
CSS3 background-image颜色渐变的实现代码
2018/09/13 HTML / CSS
H5 canvas中width、height和style的宽高区别详解
2018/11/02 HTML / CSS
帕克纽约:PARKER NY
2018/12/09 全球购物
激光脱毛、蓝光和护肤:Tria Beauty
2019/03/28 全球购物
Europcar比利时:租车
2019/08/26 全球购物
大学生实习鉴定评语
2014/04/25 职场文书
计算机多媒体专业自荐信
2014/07/04 职场文书
个人委托书怎么写
2014/09/17 职场文书
2014镇党委班子对照检查材料思想汇报
2014/09/23 职场文书
劳动纠纷调解协议书格式
2014/11/30 职场文书
秦始皇兵马俑导游词
2015/02/02 职场文书
python 学习GCN图卷积神经网络
2022/05/11 Python