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 ...
随机推荐
- linux之软连接 硬链接 link ln
p.p1 { margin: 0; font: 12px "Helvetica Neue"; color: rgba(220, 161, 13, 1) } p.p2 { margi ...
- 滑动窗口通用解leetcode字符串匹配问题
滑动窗口,这玩意解决一些字符串匹配的题目是真的挺好用的,虽然本质还是双指针. 思路: 1.维护一个窗口,不断的向右边移动 2.满足要求后,移动左边,当不满足时,跳出. 3.重复1,2.得出答案. 下面 ...
- XCTF Guess-the-Number
一.发现是jar文件,一定想到反汇编gdui这个工具,而且运行不起来,可能是我电脑问题,我就直接反编译出来了. 也发现了flag,和对应的算法,直接拉出来,在本地运行,后得到flag 二.java代码
- Elasticsearch-04-master选举
3.2 master选举机制 3.2.1 选举算法 1)bully算法 核心思想 假定所有的节点都具有一个可以比较的ID,通过比较这个ID来选举master 流程说明 节点向所有比自己ID大的节点发送 ...
- 记两道最近做的pwn题(ciscn_2019)
这两题为什么要记录呢,一个是我发现网上很多教程没写清楚(也可能是我太菜了),二是细节点很多,不同的大佬方式不太一样,有很多细节需要注意 ciscn_2019_es_2 这题是栈迁移的题,先上exp 1 ...
- LeetCode解题记录(贪心算法)(二)
1. 前言 由于后面还有很多题型要写,贪心算法目前可能就到此为止了,上一篇博客的地址为 LeetCode解题记录(贪心算法)(一) 下面正式开始我们的刷题之旅 2. 贪心 763. 划分字母区间(中等 ...
- Python使用笔记27--mysql操作封装类
1.面向过程 1 import pymysql 2 3 #面向过程 4 mysql_info = {'host':'127.0.0.1', 5 'port':3306, 6 'user':'root' ...
- python 得到汉字的拼音
import pypinyin # 不带声调的(style=pypinyin.NORMAL) def pinyin(word): s = '' for i in pypinyin.pinyin(wor ...
- OSPF的基本工作原理
OSPF的基本工作原理 1.定义 2.特点 3.基本概念 4.OSPF五种分组类型 5.DR/BDR 6.区域 1.定义 开放最短路径优先OSPF,是为了克服RIP的缺点在1989年开发出来的. &q ...
- File类与常用IO流第八章——缓冲流
第八章.缓冲流 缓冲流概述 缓冲流,也叫高效流,是对4个基本的FileXxx流的增强.按照数据类型分为4类: 输入缓冲流 输出缓冲流 字节缓冲流 BufferedInputStream Buffe ...