网站是怎么屏蔽脏话的呢:简单学会SpringBoot项目敏感词违规词过滤方案

Posted yumuing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网站是怎么屏蔽脏话的呢:简单学会SpringBoot项目敏感词违规词过滤方案相关的知识,希望对你有一定的参考价值。

一个社区最重要的就是交流氛围与审查违规,而这两者都少不了对于敏感词进行过滤的自动维护措施。基于这样的措施,我们才能基本保证用户在使用社区的过程中,不至于被敏感违规词汇包围,才能够正常的进行发布帖子和评论,享受美好的社区氛围。目前,对于 springboot 项目也有较为成熟的敏感词过滤方案。

文章目录

敏感词过滤方案

本文将采用 Github 上 houbb 大神开源的 sensitive-word 工具包来进行敏感词过滤操作,它具备以下优秀特点:

  • 包含 6W+ 词库,且不断优化更新
  • 基于 fluent-api 实现,使用优雅简洁
  • 完美兼容 spring boot 项目
  • 支持自定义敏感词一对一替换成对应正常词汇
  • 支持敏感词的判断、返回、脱敏等常见操作
  • 支持全角半角互换
  • 支持英文大小写互换
  • 支持数字常见形式的互换
  • 支持中文繁简体互换
  • 支持英文常见形式的互换
  • 支持用户自定义敏感词和白名单
  • 支持数据的数据动态更新,实时生效

敏感词过滤效果如下:

它不仅可以通过自定义替换词,也就是过滤后文本的 * 号可以随意更改,如果想要删去敏感词,替换词直接选为空即可,他还可以通过自定义对应词的替换词,比如说:五星红旗指定为国家旗帜,毛主席指定为教员,示例如下:

“五星红旗迎风飘扬,毛主席的画像屹立在广场前”。变为 “国家旗帜迎风飘扬,教员的画像屹立在广场前。”

实现思路

  • 实现 sensitive-word 的配置文件
  • 利用自定义的 SensitiveWordUtil 进行封装
  • 调用 SensitiveWordUtil 即可

XML导包模板:

<!-- 敏感词工具包 -->
<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>sensitive-word</artifactId>
    <version>0.2.1</version>
</dependency>

sensitive-word 配置是通过 SensitiveWordBs.newInstance() 进行配置的,它传回的是 SensitiveWordBs 对象,而不是默认的 SensitiveWordHelper 对象。配置类注意添加 @Configuration 注解

它的配置项如下:

序号方法说明默认值
1ignoreCase忽略大小写true
2ignoreWidth忽略半角圆角true
3ignoreNumStyle忽略数字的写法true
4ignoreChineseStyle忽略中文的书写格式true
5ignoreEnglishStyle忽略英文的书写格式true
6ignoreRepeat忽略重复词false
7enableNumCheck是否启用数字检测。true
8enableEmailCheck是有启用邮箱检测true
9enableUrlCheck是否启用链接检测true
10numCheckLen数字检测,自定义指定长度。8

在完成配置之前,我们可以先添加两个词库文本,作为自定义的敏感词库以及非敏感词库,第一个词库大家都理解,为什么还要定义非敏感词库呢?因为默认的 6w+ 敏感词中免不了存在部分在社区业务中不算过于敏感的词汇,想要予以保留,这样的话,我们就需要使用非敏感词库进行排除。当然,敏感词库不能够频繁更新以及初始化,会耗费过多的时间和性能。这两个词库放置在 resource 目录下,博主使用的是 jdk17 ,所以采用 NIO 进行文件读取,简洁高效。两个文件名称如下:

  • myAllowWords.txt:非敏感词库
  • mySensitiveWords.txt:敏感词库

要使 sensitive-word 配置上自定义两个词库内容,必须分别继承以下两个接口:

  • IWordDeny:敏感词继承方法
  • IWordAllow:非敏感词继承方法

不仅需要实现这两个接口,还要配置默认词库、自定义词库合并的词库,否则,如果在 SensitiveWordBs.newInstance() 直接配置继承方法,就只生效自定义词库。合并词库的方法为:WordDenys.chains(),默认词库分别为WordDenys.system()、WordAllows.system(),合并后词库分别赋值给 IWordDeny、IWordAllow

模板配置如下:

// 自定义敏感词
// 注意每一行为一个敏感词,单行不能只包括空格,否则,也会把空格识别为敏感词
public class MyWordDeny implements IWordDeny 

    @Override
    public List<String> deny() 
        List<String> list = new ArrayList<String>();;
        try 
            Resource mySensitiveWords = new ClassPathResource("mySensitiveWords.txt");
            Path mySensitiveWordsPath = Paths.get(mySensitiveWords.getFile().getPath());
            list =  Files.readAllLines(mySensitiveWordsPath, StandardCharsets.UTF_8);
         catch (IOException ioException) 
            logger.error("读取敏感词文件错误!"+ ioException.getMessage());
        
        return list;
    



// 自定义非敏感词
// 注意每一行为一个非敏感词,单行不能只包括空格,否则,也会把空格识别为非敏感词
public class MyWordAllow implements IWordAllow 

    @Override
    public List<String> allow() 
        List<String> list = new ArrayList<String>();;
        try 
            Resource myAllowWords = new ClassPathResource("myAllowWords.txt");
            Path myAllowWordsPath = Paths.get(myAllowWords.getFile().getPath());
            list =  Files.readAllLines(myAllowWordsPath, StandardCharsets.UTF_8);
         catch (IOException ioException) 
            logger.error("读取非敏感词文件错误!"+ ioException.getMessage());
        
        return list;
    



// 配置默认敏感词 + 自定义敏感词
IWordDeny wordDeny = WordDenys.chains(WordDenys.system(), new MyWordDeny());
// 配置默认非敏感词 + 自定义非敏感词
IWordAllow wordAllow = WordAllows.chains(WordAllows.system(), new MyWordAllow());

而自定义替换规则就必须继承并实现 ISensitiveWordReplace 接口其中的 replace() 方法。实现模板代码如下:

public class mySensitiveWordReplace implements ISensitiveWordReplace 
    @Override
    public String replace(ISensitiveWordReplaceContext context) 
        String sensitiveWord = context.sensitiveWord();
        // 自定义不同的敏感词替换策略,可以从数据库等地方读取
        if("五星红旗".equals(sensitiveWord)) 
            return "国家旗帜";
        
        if("毛主席".equals(sensitiveWord)) 
            return "教员";
        

        // 其他默认使用 * 代替
        int wordLength = context.wordLength();
        return CharUtil.repeat('*', wordLength);
    

最后就是通过 SensitiveWordBs.newInstance() 进行配置,模板代码如下:

@Bean
public SensitiveWordBs sensitiveWordBs()
    return SensitiveWordBs.newInstance()
            // 忽略大小写
            .ignoreCase(true)
            // 忽略半角圆角
            .ignoreWidth(true)
            // 忽略数字的写法
            .ignoreNumStyle(true)
            // 忽略中文的书写格式:简繁体
            .ignoreChineseStyle(true)
            // 忽略英文的书写格式
            .ignoreEnglishStyle(true)
            // 忽略重复词
            .ignoreRepeat(false)
            // 是否启用数字检测
            .enableNumCheck(true)
            // 是否启用邮箱检测
            .enableEmailCheck(true)
            // 是否启用链接检测
            .enableUrlCheck(true)
            // 数字检测,自定义指定长度
            .numCheckLen(8)
            // 配置自定义敏感词
            .wordDeny(wordDeny)
            // 配置非自定义敏感词
            .wordAllow(wordAllow)
            .init();

配置完成之后,我们就可以使用 SensitiveWordUtil 进行封装使用了,实现代码如下:

@Component
public class SensitiveWordUtil 
    @Autowired
    private SensitiveWordBs sensitiveWordBs;

    // 刷新敏感词库与非敏感词库缓存
    public void refresh()
        sensitiveWordBs.init();
    
    // 判断是否含有敏感词
    public boolean contains(String text)
        return sensitiveWordBs.contains(text);
    

    // 指定替换符进行替换敏感词
    public String replace(String text, char replaceChar)
        return sensitiveWordBs.replace(text,replaceChar);
    

    // 使用默认替换符 * 进行替换敏感词
    public String replace(String text)
        return sensitiveWordBs.replace(text);
    

    // 返回所有敏感词
    public List<String> findAll(String text)
        return sensitiveWordBs.findAll(text);
    

调用就不用说明了吧,我们敏感词过滤的部分就完成了。放一下 API 文档

方法参数返回值说明
contains(String)待验证的字符串布尔值验证字符串是否包含敏感词
replace(String, ISensitiveWordReplace)使用指定的替换策略替换敏感词字符串返回脱敏后的字符串
replace(String, char)使用指定的 char 替换敏感词字符串返回脱敏后的字符串
replace(String)使用 * 替换敏感词字符串返回脱敏后的字符串
findAll(String)待验证的字符串字符串列表返回字符串中所有敏感词
findFirst(String)待验证的字符串字符串返回字符串中第一个敏感词
findAll(String, IWordResultHandler)IWordResultHandler 结果处理类字符串列表返回字符串中所有敏感词
findFirst(String, IWordResultHandler)IWordResultHandler 结果处理类字符串返回字符串中第一个敏感词

测试方法:

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class SensitiveTest 
	@Autowired
    private SensitiveWordUtil sensitiveWordUtil;
    @Test
    public void utilTest02()
        String result = sensitiveWordUtil.replace("法网恢恢 哇 nnd 复活");
        System.out.println(result);
    

Python写各大聊天系统的屏蔽脏话功能原理

突然想到一个视频里面弹幕被和谐的一满屏的*号觉得很有趣,然后就想用python来试试写写看,结果还真玩出了点效果,思路是首先你得有一个脏话存放的仓库好到时候检测,那么个人还是喜欢用列表,因为列表灵活使用扩展都很方便,有了脏话库我们在来想核心怎么屏蔽脏话,你要记得玩家输入的弹幕数据类型是什么首档其次是字符串如果没有特殊要求就它了,万变不离其中总是这几个数据结构嘛,有了字符串替换*号什么的都轻松许多了对吧,今天所聊的是完整的一套结构,为了让大家更清晰学会,我会拆分代码然后在组装起来讲,这样大家就会有个更深了了解首先来看看核心的功能替换脏话代码如下:


#!/usr/bin/env python# -*- coding:utf-8 -*-import datetime
time = datetime.datetime.now()

speak = ‘你个狗日的,fuckR你妈哟,操你个仙人板板,个老麻批‘dirty = [‘fuck‘,‘狗日的‘,‘犊子‘,‘麻批‘,‘仙人板板‘,‘R你妈‘,‘操你‘,‘草你‘]for i in dirty:
    speak = speak.replace(i,‘*‘)print speak+" | "+str(time)


技术分享

是不是简单轻松的就把脏话给屏蔽掉了呢,这导入了时间模块datetime用来获取现在本地时间,后面会用来写入日志保存,当然很多游戏对话里面也会显示当前时间,然后speak是玩家要输出的脏话(现在是演示后面会改成Input真正的输入交互),dirty是定义的脏话库(当然没写太多因为每地域都不同太多了写不完),后面跟一个for循环来检索,只要你说的话里面包含脏话库内,那么我们就用replace替换掉,最后打印也就等于公屏上显示的字幕都是*了...当然我们还要想那如何去跟踪是谁什么时间都说了什么,这样关联就要用到类了,肯定会有疑惑为什么用类,首先类class是一类(比如桌子有方桌、圆桌、会议桌、办公桌等)事物描述的概括,例如一群玩家Player,他们都有各自的游戏名字name,然后都具有聊天功能(我们又称之为动作),这样就既可以分类又可以达到区分的效果。代码如下:


class Player(object):    def __init__(self,name):
        self.name = name    def talk(self):
        self.string = ‘whatever fuck no joke‘
        self.log()
        self.string = self.string.replace(‘fuck‘,‘雅蠛蝶‘)        print "公屏显示:%s--%s"%(self.name,self.string) 

    def log(self):        print "日志记录为:%s--%s"%(self.name,self.string)

t1 = Player(‘white‘)
t1.talk()


技术分享

这里就很全面的介绍了类的使用及工作流程效果,这里先创建一个类Player玩家类,init初始化他的名字name,其中他具备聊天功能talk,还具备日志记录功能,那么来聊天运作流程,每个玩家注册后登录游戏会有一个游戏名字(你可以理解为登录QQ后),这里self.name=name等于获取到你的个人名称(网名),然后打聊天窗口进入talk,self.string你输入的聊天信息,self.log记录日志,重点是优先把你原本的话记入到聊天日志中这样查可以查到你的记录,self.string.replace替换掉你说的脏话,那么屏幕上只会显示替换后的话语例如这打印的本来是fuck编程了雅蠛蝶...这个工作流程是不是很清晰了呢,当然你不了解类方法这里就会很迷糊了,慢慢来只要有这个思路学了类以后就很轻松了。当然不会这样就结束,最后把基本的完整代码放出来代码如下:

 

import datetime

time = str(datetime.datetime.now())[:-7]

dirty = [‘fuck‘,‘狗日的‘,‘犊子‘,‘麻批‘,‘仙人板板‘,‘R你妈‘,‘操你‘,‘草你‘]class Player(object):    def __init__(self,name):
        self.name = name    def talk(self):
        self.string = raw_input("input-write:")        # self.string = ‘你个狗日的,R你妈哟,操你个仙人板板,个老麻批‘        self.log()        for i in dirty:
            self.string = self.string.replace(i,‘雅蠛蝶‘)        print "{}  {}-speak:{}".format(time,self.name,self.string,)    def log(self):
        with open(‘zanghua.txt‘,‘a‘) as f:
            f.write("{}  {}-speak:{}\n".format(time,self.name,self.string))


t1 = Player(‘white‘)
t2 = Player(‘black‘)
t3 = Player(‘green‘)while True:
    n = raw_input(‘change Player:‘)    if n == ‘1‘:
        t1.talk()    elif n == ‘2‘:
        t2.talk()    elif n == ‘3‘:
        t3.talk()    elif n == ‘q‘:        print ‘Bye‘
        break
    else:        print "尼玛在逗我?"


测试结果如下:

技术分享

技术分享

你可以新建一个文件名叫zanghua.txt空文本就行,只是用来演示存储日志的行为效果,上面打印说change Player是为了演示不同用户输入做了个简易切换,实际上的系统你登录后很少切换用户之类的,就只是当前帐号聊天了,这里的代码就添加文件处理方式with open (文件名,打开模式) 简称为 f之类的然后写入write(记得在写入的最后加上\n换行符,不然全写第一行很难认)关于datetime[:7]切片 把上面打印时候时间后面的余数给忽略掉更简洁点。基本上的流程如此,当然可以有很多扩展,例如脏话次数超过多少禁止发言,限制发言几分钟啊,日志方面可以定时清空啊等等。这就看大家自己去研究了,代码量就有点大了这里就不展示了。最后我要说明的图如下,有很多人估计误解了些点什么。。

技术分享

 这只是演示流程的思路(提供给入门开发的新手参考),请大佬们不要误解。

最后还是老台词感谢观看,下次再见~~~!!!

本文出自 “马哥Linux培训” 博客,请务必保留此出处http://mageedu.blog.51cto.com/4265610/1972164

以上是关于网站是怎么屏蔽脏话的呢:简单学会SpringBoot项目敏感词违规词过滤方案的主要内容,如果未能解决你的问题,请参考以下文章

Python写各大聊天系统的屏蔽脏话功能原理

springBoot实现脏话屏蔽功能

WIN7系统屏蔽不良网站的方法

谷歌浏览器右上角的加号按钮可以把网页安装成APP,怎么把个人网站让谷歌浏览器识别可以安装的呢?

网站左上角的小图标是怎么做的呢?

apache2.4怎么屏蔽其他域名