网站是怎么屏蔽脏话的呢:简单学会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 注解
它的配置项如下:
| 序号 | 方法 | 说明 | 默认值 |
|---|---|---|---|
| 1 | ignoreCase | 忽略大小写 | true |
| 2 | ignoreWidth | 忽略半角圆角 | true |
| 3 | ignoreNumStyle | 忽略数字的写法 | true |
| 4 | ignoreChineseStyle | 忽略中文的书写格式 | true |
| 5 | ignoreEnglishStyle | 忽略英文的书写格式 | true |
| 6 | ignoreRepeat | 忽略重复词 | false |
| 7 | enableNumCheck | 是否启用数字检测。 | true |
| 8 | enableEmailCheck | 是有启用邮箱检测 | true |
| 9 | enableUrlCheck | 是否启用链接检测 | true |
| 10 | numCheckLen | 数字检测,自定义指定长度。 | 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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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 {@Autowiredprivate 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 {@Autowiredprivate SensitiveWordUtil sensitiveWordUtil;@Testpublic void utilTest02(){String result = sensitiveWordUtil.replace("法网恢恢 哇 nnd 复活");System.out.println(result);}
}

相关文章:
网站是怎么屏蔽脏话的呢:简单学会SpringBoot项目敏感词、违规词过滤方案
一个社区最重要的就是交流氛围与审查违规,而这两者都少不了对于敏感词进行过滤的自动维护措施。基于这样的措施,我们才能基本保证用户在使用社区的过程中,不至于被敏感违规词汇包围,才能够正常的进行发布帖子和评论,享…...
kafka经典面试题
这里写目录标题1.生产者1.1 生产者发送原理1.2 分区有什么好处?1.3 生产消息时, 是如何决定消息落盘到哪个分区的?1.4 生产者如何提高吞吐量1.5 如何保证生产的消息不丢失(能成功落盘)1.6 ack为-1, 就肯定不会丢失数据吗?1.7 生产者重复发送消息的场景1.8 生产者如何保证数据…...
我的CSDN笔记总索引(阅读量降序,代码自动遍历生成HTML5源码)
Python代码用Linux命令行工具crul获取CSDN博文页面源码,Python内置re正则解析出博文笔记信息。 (本文获得CSDN质量评分【xx】)【学习的细节是欢悦的历程】Python 官网:https://www.python.org/ Free:大咖免费“圣经”教程《 python 完全自学…...
修改Windows hosts文件的解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...
愤怒的Spring(三)Idaea Maven搭建Spring并运行项目(超详细,超全)
愤怒的Spring(三) 一、目录结构 环境搭配与上一篇内容一样,详情请看愤怒的Spring(二)Idaea Maven搭建Spring并运行项目(超详细,超全)https://blog.csdn.net/sz710211849/article/d…...
NDK(三):JNIEnv解析
文章目录一、概述二、JNIEnv结构体三、JNINativeInterface结构体3.1 Class操作3.2 反射操作3.3 对象字段 & 方法操作3.4 类的静态字段 & 静态方法操作3.5 字符串操作3.6 锁操作3.7 数组操作3.8 注册和反注册native方法3.9 异常Exception操作3.10 引用的操作3.11 其它四…...
禅道——图文安装及使用教程
👨💻作者简介:练习时长两年半的java博主 📖个人主页:君临๑ 🎞️文章介绍:禅道的2023版安装图文教程 🎁 如果文章对你有用,就点个免费的赞吧👍 目录 一、搜…...
Java基础——枚举类enum
枚举类是一种特殊的数据类型,可以理解为一个数组,数组成员为特定的对象枚举类不能在外面创建对象,在类里面就包含了一组特定的对象,每个对象有着相同数量的属性枚举类的对象放在最前面,且对象们的顺序就是对应的索引枚…...
【机器学习】一文了解如何评估和选择最佳机器学习模型并绘制ROC曲线?
一文了解如何评估和选择最佳机器学习模型? 问ChatGPT:如何选择最佳机器学习模型?问ChatGPT:评估机器学习模型有哪些指标?0. 引言1. 混淆矩阵2. 评价指标3. ROC与AUC4. PR(precision recall )曲线参考资料问ChatGPT:如何选择最佳机器学习模型? 选择最佳机器学习模型是机…...
vue3 笔记
watchEffect 的起源 stackoverflow - watchEffect vs. watch watch behavior in v3 is different to v2Change watch Options API to trigger immediately vue3 最初只有 watch ,没有 watchEffect。这个时候的 watch 默认是 immediate true,可以 wat…...
第12章_MySQL数据类型精讲
第12章_MySQL数据类型精讲 🏠个人主页:shark-Gao 🧑个人简介:大家好,我是shark-Gao,一个想要与大家共同进步的男人😉😉 🎉目前状况:23届毕业生,…...
二叉树路径总和第一题
1题目 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。 叶子节点 是指没有…...
@RefreshScope源码解析
前言 RefeshScope这个注解想必大家都用过,在微服务配置中心的场景下经常出现,它可以用来刷新Bean中的属性配置,那么它是如何做到的呢?让我们来一步步揭开它神秘的面纱。 RefreshScope介绍 就是说我们在修改了bean属性的时候项目…...
【开发】后端框架——Spring
前置知识:JSP&Servlet 学习视频:https://www.bilibili.com/video/BV1WE411d7Dv?spm_id_from333.999.0.0 IoC:控制反转 IoC的理解:IoC思想,IoC怎么创建对象,IoC是Spring的核心 依赖注入三种方式&#x…...
vue中的自定义指令
前言 说到 vue 中的自定义指令,相信大家都不陌生。在官网中是这么说的,除了核心功能默认内置的指令 (v-model 和 v-show),vue 也允许注册自定义指令。那什么时候会用到自定义指令呢?代码复用和抽象的主要形式是组件。然而…...
技术分享及探讨
前言 很高兴给大家做一个技术分享及探讨。 下面给大家分享几个工作遇到有趣的例子。 docker docker 进程 现象 客户的模型导入到BML平台发布预测服务后,模型本身是用django提供的支持。按照本地docker的方式进行调试,kill掉django的进程修改代码…...
人工智能AI
AI 模型。它使用深度神经网络,从数十亿或数万亿个单词中学习,能够生成任何主题或领域的文本。它可以执行各种自然语言任务,如分类、总结、翻译、生成和对话。 大语言模型开发建立在4个核心思想上: 模型 – Models 提示词 - Prompt…...
2022天梯赛补题
题目详情 - L2-041 插松枝 (pintia.cn) 思路:模拟 背包就是个栈,开个stack解决流程思路是,每次取推进器前,尽可能拿背包的,背包拿到不可以时,跳出拿推进器时判断: 如果背包装得下,…...
字节跳动测试岗面试挂在2面,复盘后,我总结了失败原因,决定再战一次...
先说下我基本情况,本科不是计算机专业,现在是学通信,然后做图像处理,可能面试官看我不是科班出身没有问太多计算机相关的问题,因为第一次找工作,字节的游戏专场又是最早开始的,就投递了…...
Nodejs实现通用的加密和哈希算法(MD5、SHA1、Hmac、AES、Diffie-Hellman、RSA),crypto模块详解
crypto crypto模块的目的是为了提供通用的加密和哈希算法(hash)。用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢。Nodejs用C/C++实现这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。 MD5和SHA1 MD5是一种常用的哈希算法,…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
