SpringBoot开发十四-过滤敏感词
项目需求—过滤敏感词
利用 Tire 树实现过滤敏感词
定义前缀树,根据敏感词初始化前缀树,编写过滤敏感词的方法
代码实现
我们首先把敏感词存到一个文件 sensitive.txt:
赌博
嫖娼
吸毒
开票
然后我们写一个工具 SensitiveFilter 实现这个功能:
package com.nowcoder.community.util; import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map; @Component
public class SensitiveFilter {
private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class); // 替换符
private static final String REPLACEMENT = "***"; // 根节点
private TrieNode rootNode = new TrieNode(); @PostConstruct
public void init() {
try (
InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
) {
String keyword;
while ((keyword = reader.readLine()) != null) {
// 添加到前缀树
this.addKeyword(keyword);
}
} catch (IOException e) {
logger.error("加载敏感词文件失败: " + e.getMessage());
}
} // 将一个敏感词添加到前缀树中
private void addKeyword(String keyword) {
TrieNode tempNode = rootNode;
for (int i = 0; i < keyword.length(); i++) {
char c = keyword.charAt(i);
TrieNode subNode = tempNode.getSubNode(c); if (subNode == null) {
// 初始化子节点
subNode = new TrieNode();
tempNode.addSubNode(c, subNode);
} // 指向子节点,进入下一轮循环
tempNode = subNode; // 设置结束标识
if (i == keyword.length() - 1) {
tempNode.setKeywordEnd(true);
}
}
} /**
* 过滤敏感词
*
* @param text 待过滤的文本
* @return 过滤后的文本
*/
public String filter(String text) {
if (StringUtils.isBlank(text)) {
return null;
} // 指针1
TrieNode tempNode = rootNode;
// 指针2
int begin = 0;
// 指针3
int position = 0;
// 结果
StringBuilder sb = new StringBuilder(); while (position < text.length()) {
char c = text.charAt(position); // 跳过符号
if (isSymbol(c)) {
// 若指针1处于根节点,将此符号计入结果,让指针2向下走一步
if (tempNode == rootNode) {
sb.append(c);
begin++;
}
// 无论符号在开头或中间,指针3都向下走一步
position++;
continue;
} // 检查下级节点
tempNode = tempNode.getSubNode(c);
if (tempNode == null) {
// 以begin开头的字符串不是敏感词
sb.append(text.charAt(begin));
// 进入下一个位置
position = ++begin;
// 重新指向根节点
tempNode = rootNode;
} else if (tempNode.isKeywordEnd()) {
// 发现敏感词,将begin~position字符串替换掉
sb.append(REPLACEMENT);
// 进入下一个位置
begin = ++position;
// 重新指向根节点
tempNode = rootNode;
} else {
// 检查下一个字符
position++;
}
} // 将最后一批字符计入结果
sb.append(text.substring(begin)); return sb.toString();
} // 判断是否为符号
private boolean isSymbol(Character c) {
// 0x2E80~0x9FFF 是东亚文字范围
return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
} // 前缀树
private class TrieNode { // 关键词结束标识
private boolean isKeywordEnd = false; // 子节点(key是下级字符,value是下级节点)
private Map<Character, TrieNode> subNodes = new HashMap<>(); public boolean isKeywordEnd() {
return isKeywordEnd;
} public void setKeywordEnd(boolean keywordEnd) {
isKeywordEnd = keywordEnd;
} // 添加子节点
public void addSubNode(Character c, TrieNode node) {
subNodes.put(c, node);
} // 获取子节点
public TrieNode getSubNode(Character c) {
return subNodes.get(c);
} }
}
然后写个测试类 SensitiveTests 测试一下:
package com.nowcoder.community; import com.nowcoder.community.util.SensitiveFilter;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class SensitiveTests {
@Autowired
private SensitiveFilter sensitiveFilter; @Test
public void testSensitiveFilter() {
String text = "这里可以赌博,可以嫖娼,可以吸毒,可以开票,哈哈哈!";
text = sensitiveFilter.filter(text);
System.out.println(text); text = "这里可以☆赌☆博☆,可以☆嫖☆娼☆,可以☆吸☆毒☆,可以☆开☆票☆,哈哈哈!";
text = sensitiveFilter.filter(text);
System.out.println(text);
}
}
SpringBoot开发十四-过滤敏感词的更多相关文章
- 【SpringBoot】前缀树 Trie 过滤敏感词
1.过滤敏感词 Spring Boot实践,开发社区核心功能 完成过滤敏感词 Trie 名称:Trie也叫做字典树.前缀树(Prefix Tree).单词查找树 特点:查找效率高,消耗内存大 应用:字 ...
- (转)两种高效过滤敏感词算法--DFA算法和AC自动机算法
原文:https://blog.csdn.net/u013421629/article/details/83178970 一道bat面试题:快速替换10亿条标题中的5万个敏感词,有哪些解决思路? 有十 ...
- SpringBoot开发十五-发布帖子
需求介绍 使用 AJAX 异步通信实现网页能够增量的更新呈现到页面上而不需要刷新整个页面. 现在基本上都是服务器返回 JSON 字符串来解析 代码实现 使用 JQuery 发送 AJAX 请求. 首先 ...
- web前端js过滤敏感词
web前端js过滤敏感词 这里是用文本输入框还有文本域绑定了失去焦点事件,然后再遍历敏感词数组进行匹配和替换. var keywords=["阿扁","呵呵", ...
- 过滤敏感词工具类SensitiveFilter
网上过滤敏感词工具类有的存在挺多bug,这是我自己改用的过滤敏感词工具类,目前来说没啥bug,如果有bug欢迎在评论指出 使用前缀树 Trie 实现的过滤敏感词,树节点用静态内部类表示了,都写在一个 ...
- STC8H开发(十四): I2C驱动RX8025T高精度实时时钟芯片
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
- [转]Filter实现处理中文乱码,转义html标签,过滤敏感词
原文地址:http://www.cnblogs.com/xdp-gacl/p/3952405.html 在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可 ...
- SpringBoot开发十九-添加评论
需求介绍 熟悉事务管理,并且应用到添加评论的功能. 数据层:增加评论数据,修改帖子的评论数量 业务层:处理添加评论的业务,先增加评论再更新帖子的评论数量(因为用到了两个DML操作所以要用到事务管理) ...
- js 过滤敏感词 ,可将带有标点符号的敏感词过滤掉
function transSensitive(content) { // var Sensitive = H.getStorage("Sensitive");//敏感词数组 va ...
随机推荐
- GitLab升级(yum安装版v11.11.8~12.0.12)
参考官方升级建议(注意升级路线:Example upgrade paths) 升级前请自行备份(测试可忽略此步骤) 生成备份文件,在/var/opt/gitlab/backups/目录下生成备份文件 ...
- 其他:Spring5.0框架源码导入IDEA
1.下载Spring spring-framework-5.0.4.RELEASE下载地址:https://github.com/spring-projects/spring-framework/re ...
- 自己动手模拟spring的IOC
我们这里是模拟spring,主要模拟spring中的IOC功能,所以在此我们一样要在service层中定义dao的实例,当然不用new出来,我们就通过spring的IOC把这里的dao层注入进来.不要 ...
- docker起不来报错:Failed to start Docker Application Container Engine.
报错信息如下: [root@localhost localdisk]# systemctl restart docker Job for docker.service failed because t ...
- 「AGC029C」Lexicographic constraints
「AGC029C」Lexicographic constraints 传送门 好像这个题非常 easy. 首先这个答案显然具有可二分性,所以问题转化为如何判定给定的 \(k\) 是否可行. 如果 \( ...
- 常见内部排序算法对比分析及C++ 实现代码
内部排序是指在排序期间数据元素全部存放在内存的排序.外部排序是指在排序期间全部元素的个数过多,不能同时存放在内存,必须根据排序过程的要求,不断在内存和外存之间移动的排序.本次主要介绍常见的内部排序算法 ...
- 数据库:随机显示n条记录
1.sqlite3数据库select * from QG order by random() limit 6 以下显示前10条记录 2.SQL Server数据库select top 10 * f ...
- Java基础00-接口组成更新31
1. 接口组成更新 1.1 接口组成更新概述 1.2 接口中默认方法 代码示例: 需求: 1:定义一个接口MyInterface,里面有两个抽象方法: void show1(); void show2 ...
- Java基础00-常用API24
1. Math Math 1.1 Math类概述 1.2 Math类的常用方法 返回绝对值:是正数是时候直接返回参数本身,是负值的时候返回的是参数的相反数.参数是10时返回的是10,参数是-10的时候 ...
- springMVC-10-文件上传
导入依赖(注意会和servlet-api依赖冲突) <!--文件上传jar包, 前面已导过servlet-api需排除--> <dependency> <groupId& ...