python过滤敏感词汇_Python过滤敏感词汇

article/2025/9/30 22:04:36

1.replace过滤

最简单也是最直接的就是直接循环敏感词,然后使用replace过滤关键词,文章和敏感词少的时候还可以,多的时候效率就真的很一般了。

2.使用正则过滤

有两个技术要点,

1.使用Python正则表达式的re的sub()函数;

2.在正则表达式语法中,竖线“|”表示二选一或多选一。

代码参考

Python

1

2

3

4

5

6

7

8

importre

defcheck_filter(keywords,text):

returnre.sub("|".join(keywords),"***",text)

keywords=("暴力","色情","其他关键字")

text="这句话里不包含暴力,也不包含色情,但是可能包含其他关键字"

print(check_filter(keywords,text))

返回结果

Python

1

2

这句话里不包含***,也不包含***,但是可能包含***

3.DFA过滤敏感词算法

在网上查了下敏感词过滤方案,找到了一种名为DFA的算法,即 Deterministic Finite Automaton 算法,翻译成中文就是确定有穷自动机算法。它的基本思想是基于状态转移来检索敏感词,只需要扫描一次待检测文本,就能对所有敏感词进行检测,所以效率比方案一高不少。

假设我们有以下5个敏感词需要检测:傻逼、傻子、傻大个、坏蛋、坏人。那么我们可以先把敏感词中有相同前缀的词组合成一个树形结构,不同前缀的词分属不同树形分支,以上述5个敏感词为例,可以初始化成如下2棵树:

fe1910739e3274b317cd8cae8d120032.png

25e160101c8a817e6ca55f80a3fdb224.png

把敏感词组成成树形结构有什么好处呢?最大的好处就是可以减少检索次数,我们只需要遍历一次待检测文本,然后在敏感词库中检索出有没有该字符对应的子树就行了,如果没有相应的子树,说明当前检测的字符不在敏感词库中,则直接跳过继续检测下一个字符;如果有相应的子树,则接着检查下一个字符是不是前一个字符对应的子树的子节点,这样迭代下去,就能找出待检测文本中是否包含敏感词了。

我们以文本“你是不是傻逼”为例,我们依次检测每个字符,因为前4个字符都不在敏感词库里,找不到相应的子树,所以直接跳过。当检测到“傻”字时,发现敏感词库中有相应的子树,我们把他记为tree-1,接着再搜索下一个字符“逼”是不是子树tree-1的子节点,发现恰好是,接下来再判断“逼”这个字符是不是叶子节点,如果是,则说明匹配到了一个敏感词了,在这里“逼”这个字符刚好是tree-1的叶子节点,所以成功检索到了敏感词:“傻逼”。大家发现了没有,在我们的搜索过程中,我们只需要扫描一次被检测文本就行了,而且对于被检测文本中不存在的敏感词,如这个例子中的“坏蛋”和“坏人”,我们完全不会扫描到,因此相比方案一效率大大提升了。

在python中,我们可以用dict来存储上述的树形结构,还是以上述敏感词为例,我们把每个敏感词字符串拆散成字符,再存储到dict中,可以这样存:

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

{

'傻':{

'逼':{

'\x00':0

},

'子':{

'\x00':0

},

'大':{

'个':{

'\x00':0

}

}

},

'坏':{

'蛋':{

'\x00':0

},

'人':{

'\x00':0}

}

}

首先将每个词的第一个字符作为key,value则是另一个dict,value对应的dict的key为第二个字符,如果还有第三个字符,则存储到以第二个字符为key的value中,当然这个value还是一个dict,以此类推下去,直到最后一个字符,当然最后一个字符对应的value也是dict,只不过这个dict只需要存储一个结束标志就行了,像上述的例子中,我们就存了一个{'\x00': 0}的dict,来表示这个value对应的key是敏感词的最后一个字符。

同理,“坏人”和“坏蛋”这2个敏感词也是按这样的方式存储起来,这里就不罗列出来了。

用dict存储有什么好处呢?我们知道dict在理想情况下可以以O(1)的时间复杂度进行查询,所以我们在遍历待检测字符串的过程中,可以以O(1)的时间复杂度检索出当前字符是否在敏感词库中,效率比方案一提升太多了。

接下来上代码。

Python

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

# -*- coding:utf-8 -*-

importtime

time1=time.time()

# DFA算法

classDFAFilter(object):

def__init__(self):

self.keyword_chains={}# 关键词链表

self.delimit='\x00'# 限定

defadd(self,keyword):

keyword=keyword.lower()# 关键词英文变为小写

chars=keyword.strip()# 关键字去除首尾空格和换行

ifnotchars:# 如果关键词为空直接返回

return

level=self.keyword_chains

# 遍历关键字的每个字

foriinrange(len(chars)):

# 如果这个字已经存在字符链的key中就进入其子字典

ifchars[i]inlevel:

level=level[chars[i]]

else:

ifnotisinstance(level,dict):

break

forjinrange(i,len(chars)):

level[chars[j]]={}

last_level,last_char=level,chars[j]

level=level[chars[j]]

last_level[last_char]={self.delimit:0}

break

ifi==len(chars)-1:

level[self.delimit]=0

defparse(self,path):

withopen(path,encoding='utf-8')asf:

forkeywordinf:

self.add(str(keyword).strip())

print(self.keyword_chains)

deffilter(self,message,repl="*"):

message=message.lower()

ret=[]

start=0

whilestart

level=self.keyword_chains

step_ins=0

forchar inmessage[start:]:

ifchar inlevel:

step_ins+=1

ifself.delimit notinlevel[char]:

level=level[char]

else:

ret.append(repl*step_ins)

start+=step_ins-1

break

else:

ret.append(message[start])

break

else:

ret.append(message[start])

start+=1

return''.join(ret)

if__name__=="__main__":

gfw=DFAFilter()

path="E:/lyh/test/sensitive_words.txt"

gfw.parse(path)

text="你真是个大傻逼,大傻子,傻大个,大坏蛋,坏人。"

result=gfw.filter(text)

print(text)

print(result)

time2=time.time()

print('总共耗时:'+str(time2-time1)+'s')

sensitive_words.txt

Python

1

2

3

4

5

6

傻逼

傻子

傻大个

坏蛋

坏人

运行结果

Python

1

2

3

4

你真是个大傻逼,大傻子,傻大个,大坏蛋,坏人。

你真是个大**,大**,***,大**,**。

总共耗时:0.0009999275207519531s

4.AC自动机过滤敏感词算法

AC自动机:一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。

简单地讲,AC自动机就是字典树+kmp算法+失配指针

Python

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

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

# -*- coding:utf-8 -*-

importtime

time1=time.time()

# AC自动机算法

classnode(object):

def__init__(self):

self.next={}

self.fail=None

self.isWord=False

self.word=""

classac_automation(object):

def__init__(self):

self.root=node()

# 添加敏感词函数

defaddword(self,word):

temp_root=self.root

forchar inword:

ifchar notintemp_root.next:

temp_root.next[char]=node()

temp_root=temp_root.next[char]

temp_root.isWord=True

temp_root.word=word

# 失败指针函数

defmake_fail(self):

temp_que=[]

temp_que.append(self.root)

whilelen(temp_que)!=0:

temp=temp_que.pop(0)

p=None

forkey,value intemp.next.item():

iftemp==self.root:

temp.next[key].fail=self.root

else:

p=temp.fail

whilepisnotNone:

ifkey inp.next:

temp.next[key].fail=p.fail

break

p=p.fail

ifpisNone:

temp.next[key].fail=self.root

temp_que.append(temp.next[key])

# 查找敏感词函数

defsearch(self,content):

p=self.root

result=[]

currentposition=0

whilecurrentposition

word=content[currentposition]

whileword inp.next==Falseandp!=self.root:

p=p.fail

ifword inp.next:

p=p.next[word]

else:

p=self.root

ifp.isWord:

result.append(p.word)

p=self.root

currentposition+=1

returnresult

# 加载敏感词库函数

defparse(self,path):

withopen(path,encoding='utf-8')asf:

forkeywordinf:

self.addword(str(keyword).strip())

# 敏感词替换函数

defwords_replace(self,text):

"""

:param ah: AC自动机

:param text: 文本

:return: 过滤敏感词之后的文本

"""

result=list(set(self.search(text)))

forxinresult:

m=text.replace(x,'*'*len(x))

text=m

returntext

if__name__=='__main__':

ah=ac_automation()

path='F:/文本反垃圾算法/sensitive_words.txt'

ah.parse(path)

text1="新疆骚乱苹果新品发布会雞八"

text2=ah.words_replace(text1)

print(text1)

print(text2)

time2=time.time()

print('总共耗时:'+str(time2-time1)+'s')

运行结果


http://chatgpt.dhexx.cn/article/HEWOpjmP.shtml

相关文章

Java Filter——敏感词汇过滤

Filter的简介 Filter也称之为过滤器,它是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例…

JavaEE之Filter过滤器、登录状态验证、敏感词汇过滤

Filter:过滤器 1. 概念: 生活中的过滤器:净水器,空气净化器web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。 过滤器的作用:一般用于完成通用的操作。如&a…

SpringBoot项目实现敏感词汇过滤

记录背景&#xff1a;SpringBoot项目实现敏感词汇过滤 一&#xff1a;敏感词汇文件放置位置 二&#xff1a;说明&#xff1a;如果txt文件不能编译&#xff0c;pom文件添加下面配置 <build><resources><resource><directory>src/main/resources</…

敏感词过滤的php代码,ThinkPHP敏感词汇过滤

如果内容中包含敏感词汇&#xff0c;则返回False&#xff0c;否则返回True。 很简单的代码。 请将文件放置于 "项目/ORG/SensitiveFilter.class.php"下。 其中 “ SensitiveThesaurus.php”是一个敏感词汇数组&#xff0c;大家可以任意添加内容。 1.[代码][PHP]代码&…

JavaWeb 敏感词汇过滤器

1&#xff0c;基本功能 在提交数据时&#xff0c;常常需要检查数据中是否含有敏感词汇&#xff0c;有的话&#xff0c;需要屏蔽敏感词汇 2&#xff0c;实现原理 我们可以使用Filter过滤器&#xff0c;对数据进行检查与处理&#xff0c;将处理完毕的数据放行。因此&#xff0c;…

Filter 敏感词汇过滤案例

文章目录 一、需求分析二、案例实现 一、需求分析 &#xff08;1&#xff09;对案例录入的数据进行敏感词汇过滤 &#xff08;2&#xff09;敏感词汇参考敏感词汇.txt &#xff08;3&#xff09;如果是敏感词汇&#xff0c;替换为 *** 可以确定 Filter 和 servlet 中的 reques…

5分钟搞定敏感词过滤!

函数工作流(FunctionGraph,FGS)是一项基于事件驱动的函数托管计算服务,托管函数具备以毫秒级弹性伸缩、免运维、高可靠的方式运行。通过函数工作流,开发者无需配置和管理服务器,只需关注业务逻辑,编写函数代码,以无服务器的方式构建应用,便能开发出一个弹性高可用的后…

基础编程题目集 7-32 说反话-加强版 (20分)

#include <stdio.h> //标准c&#xff0c;没有用c的string&#xff0c;这样首先读取字符串就是个问题了 #define MAX 500000 //先处理字符串&#xff0c;删除多余的空格&#xff0c;形成新字符串 //Hello World Here I Come int main() {char s; //指单独一个字符c…

PTA 7-32 说反话-加强版

思路&#xff1a; 读入字符串str&#xff0c;那么用output数组存储每个单词的首字母&#xff0c;及尾字母后一字母在字符串的下标。那么已知这两个数据便可以输出该单词。 考虑到逆序输出的需要&#xff0c;逆序读取字符串。 如字符串”#apple##“&#xff08;#表示空格&#…

C++ 1009 说反话(20 分)

注意点1:转载自:https://blog.csdn.net/u011421608/article/details/44591579 我们先来看一段输入流cin>>和getline混用的代码: #include<iostream> #include<string> using namespace std;int main() {int age;string name;cout<<"请输入年…

7-32 说反话-加强版

7-32 说反话-加强版&#xff08;20 分&#xff09; 给定一句英语&#xff0c;要求你编写程序&#xff0c;将句中所有单词的顺序颠倒输出。 输入格式&#xff1a; 测试输入包含一个测试用例&#xff0c;在一行内给出总长度不超过500 000的字符串。字符串由若干单词和若干空格组成…

Sql Server char nchar varchar nvarchar 区别

一、 用快捷键AltF1 打开的表结构&#xff0c; 我们看到的length, nchar和nvarchar 需要除以2才是储存的真正长度 二 、 类型前缀的意思1.有var前缀的&#xff0c;表示是实际存储空间是变长的&#xff0c;varchar,nvarchar 所谓定长就是长度固定的&#xff0c;当输入的数据长度…

Sqlserver 中nchar(n)、varchar(n)、nvarchar(n)和nvarchar(max)的区别

nchar(n): 固定大小字符串数据。 n 用于定义字符串大小&#xff08;以双字节为单位&#xff09;&#xff0c;并且它必须是 1 到 4,000 之间的值。 存储大小为 n 字节的两倍。 varchar(n): 长度为 n 个字节的可变长度且非 Unicode 的字符数据。n 必须是一个介于 1 和 8,000 之间…

通过实战探索数据库中的char、varchar、varchar2、nvarchar2的部分区别

前言 注&#xff1a;本文的实践是在oracle数据库中进行的&#xff0c;主要基于字节与字符以及定长与变长方面考虑&#xff0c;探索这四个类型的部分区别 Oracle数据库中&#xff0c;char、varchar、varchar2、nvarchar2是我们常用到的数据类型 &#xff08;MySQL中没有varch…

nvarchar 和varchar区别

有时候设计字段的时候&#xff0c;碰到nvarchar和varchar时候&#xff0c;是有点犹豫。所以今天就来探个究竟把。 (一) varchar是非Unicode可变长度类型&#xff0c;nvarchar是Unicode编码可变长度类型 DECLARE name AS VARCHAR(50)我是中国人test SELECT name AS Name, DATAL…

oracle NVARCHAR2 数据类型

参考地址 https://docs.oracle.com/cd/B19306_01/server.102/b14225/ch7progrunicode.htm#sthref807 英语不好的看中文直译 utf8可能会影响性能&#xff0c;因为它是一个可变宽度字符集。NChar字段的空白填充过多会降低性能。考虑使用nvarchar数据类型或更改为nchar数据类型的a…

【ORACLE】谈一谈NVARCHAR2、NCHAR、NCLOB等数据类型和国家字符集

一、背景 一直以来&#xff0c;很多用过ORACLE数据库的开发人员&#xff0c;都知道在ORACLE中&#xff0c;字符类型可以为varchar2&#xff0c;也可以为nvarchar2&#xff0c;但是很多人都不知道这两种类型有什么区别&#xff0c;同样还有char/nchar,clob/nclob这些&#xff0…

Oracle NCHAR与NVARCHAR2 最大字符数和最大字节数

根据官方文档和实验测试整理一下常见问题以及相关结论&#xff0c;以NVARCHAR2为主。 一、 含义及用途 NCHAR和NVARCHAR2都是Unicode数据类型&#xff0c;存储Unicode字符数据。NCHAR和NVARCHAR2数据类型的对应的国家字符集&#xff08;NLS_NCHAR_CHARACTERSET&#xff09;只能…

foreach 中如何给数组赋值

最近发现&#xff0c;在foreach中给数组赋值&#xff0c;在foreach外&#xff0c;数组是没有变化的&#xff0c;对此情况&#xff0c;有特定的处理方法&#xff0c;特此记录一下&#xff1a; 如下&#xff0c;就是在foreach中&#xff0c;加上 $res[$k] $v;给$res重新赋值&am…

数组与数组赋值

int类型数组赋值 #include<stdio.h> int main() { int a[] {1,2,3,4,5,7}; printf("a[3]%d", a[3]); return 0; } char类型数组赋值 1.直接字符串赋值 char a[] "q,0/d"; 2.逐个赋值 char b[] { d,b,3,&am…