项目需求—过滤敏感词

利用 Tire 树实现过滤敏感词

定义前缀树,根据敏感词初始化前缀树,编写过滤敏感词的方法

代码实现

我们首先把敏感词存到一个文件 sensitive.txt:

  1. 赌博
  2. 嫖娼
  3. 吸毒
  4. 开票

  

然后我们写一个工具 SensitiveFilter 实现这个功能:

  1. package com.nowcoder.community.util;
  2.  
  3. import org.apache.commons.lang3.CharUtils;
  4. import org.apache.commons.lang3.StringUtils;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.stereotype.Component;
  8.  
  9. import javax.annotation.PostConstruct;
  10. import java.io.BufferedReader;
  11. import java.io.IOException;
  12. import java.io.InputStream;
  13. import java.io.InputStreamReader;
  14. import java.util.HashMap;
  15. import java.util.Map;
  16.  
  17. @Component
  18. public class SensitiveFilter {
  19. private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);
  20.  
  21. // 替换符
  22. private static final String REPLACEMENT = "***";
  23.  
  24. // 根节点
  25. private TrieNode rootNode = new TrieNode();
  26.  
  27. @PostConstruct
  28. public void init() {
  29. try (
  30. InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
  31. BufferedReader reader = new BufferedReader(new InputStreamReader(is));
  32. ) {
  33. String keyword;
  34. while ((keyword = reader.readLine()) != null) {
  35. // 添加到前缀树
  36. this.addKeyword(keyword);
  37. }
  38. } catch (IOException e) {
  39. logger.error("加载敏感词文件失败: " + e.getMessage());
  40. }
  41. }
  42.  
  43. // 将一个敏感词添加到前缀树中
  44. private void addKeyword(String keyword) {
  45. TrieNode tempNode = rootNode;
  46. for (int i = 0; i < keyword.length(); i++) {
  47. char c = keyword.charAt(i);
  48. TrieNode subNode = tempNode.getSubNode(c);
  49.  
  50. if (subNode == null) {
  51. // 初始化子节点
  52. subNode = new TrieNode();
  53. tempNode.addSubNode(c, subNode);
  54. }
  55.  
  56. // 指向子节点,进入下一轮循环
  57. tempNode = subNode;
  58.  
  59. // 设置结束标识
  60. if (i == keyword.length() - 1) {
  61. tempNode.setKeywordEnd(true);
  62. }
  63. }
  64. }
  65.  
  66. /**
  67. * 过滤敏感词
  68. *
  69. * @param text 待过滤的文本
  70. * @return 过滤后的文本
  71. */
  72. public String filter(String text) {
  73. if (StringUtils.isBlank(text)) {
  74. return null;
  75. }
  76.  
  77. // 指针1
  78. TrieNode tempNode = rootNode;
  79. // 指针2
  80. int begin = 0;
  81. // 指针3
  82. int position = 0;
  83. // 结果
  84. StringBuilder sb = new StringBuilder();
  85.  
  86. while (position < text.length()) {
  87. char c = text.charAt(position);
  88.  
  89. // 跳过符号
  90. if (isSymbol(c)) {
  91. // 若指针1处于根节点,将此符号计入结果,让指针2向下走一步
  92. if (tempNode == rootNode) {
  93. sb.append(c);
  94. begin++;
  95. }
  96. // 无论符号在开头或中间,指针3都向下走一步
  97. position++;
  98. continue;
  99. }
  100.  
  101. // 检查下级节点
  102. tempNode = tempNode.getSubNode(c);
  103. if (tempNode == null) {
  104. // 以begin开头的字符串不是敏感词
  105. sb.append(text.charAt(begin));
  106. // 进入下一个位置
  107. position = ++begin;
  108. // 重新指向根节点
  109. tempNode = rootNode;
  110. } else if (tempNode.isKeywordEnd()) {
  111. // 发现敏感词,将begin~position字符串替换掉
  112. sb.append(REPLACEMENT);
  113. // 进入下一个位置
  114. begin = ++position;
  115. // 重新指向根节点
  116. tempNode = rootNode;
  117. } else {
  118. // 检查下一个字符
  119. position++;
  120. }
  121. }
  122.  
  123. // 将最后一批字符计入结果
  124. sb.append(text.substring(begin));
  125.  
  126. return sb.toString();
  127. }
  128.  
  129. // 判断是否为符号
  130. private boolean isSymbol(Character c) {
  131. // 0x2E80~0x9FFF 是东亚文字范围
  132. return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
  133. }
  134.  
  135. // 前缀树
  136. private class TrieNode {
  137.  
  138. // 关键词结束标识
  139. private boolean isKeywordEnd = false;
  140.  
  141. // 子节点(key是下级字符,value是下级节点)
  142. private Map<Character, TrieNode> subNodes = new HashMap<>();
  143.  
  144. public boolean isKeywordEnd() {
  145. return isKeywordEnd;
  146. }
  147.  
  148. public void setKeywordEnd(boolean keywordEnd) {
  149. isKeywordEnd = keywordEnd;
  150. }
  151.  
  152. // 添加子节点
  153. public void addSubNode(Character c, TrieNode node) {
  154. subNodes.put(c, node);
  155. }
  156.  
  157. // 获取子节点
  158. public TrieNode getSubNode(Character c) {
  159. return subNodes.get(c);
  160. }
  161.  
  162. }
  163. }

  

然后写个测试类 SensitiveTests 测试一下:

  1. package com.nowcoder.community;
  2.  
  3. import com.nowcoder.community.util.SensitiveFilter;
  4. import org.junit.Test;
  5. import org.junit.runner.RunWith;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.boot.test.context.SpringBootTest;
  8. import org.springframework.test.context.ContextConfiguration;
  9. import org.springframework.test.context.junit4.SpringRunner;
  10.  
  11. @RunWith(SpringRunner.class)
  12. @SpringBootTest
  13. @ContextConfiguration(classes = CommunityApplication.class)
  14. public class SensitiveTests {
  15. @Autowired
  16. private SensitiveFilter sensitiveFilter;
  17.  
  18. @Test
  19. public void testSensitiveFilter() {
  20. String text = "这里可以赌博,可以嫖娼,可以吸毒,可以开票,哈哈哈!";
  21. text = sensitiveFilter.filter(text);
  22. System.out.println(text);
  23.  
  24. text = "这里可以☆赌☆博☆,可以☆嫖☆娼☆,可以☆吸☆毒☆,可以☆开☆票☆,哈哈哈!";
  25. text = sensitiveFilter.filter(text);
  26. System.out.println(text);
  27. }
  28. }

  

SpringBoot开发十四-过滤敏感词的更多相关文章

  1. 【SpringBoot】前缀树 Trie 过滤敏感词

    1.过滤敏感词 Spring Boot实践,开发社区核心功能 完成过滤敏感词 Trie 名称:Trie也叫做字典树.前缀树(Prefix Tree).单词查找树 特点:查找效率高,消耗内存大 应用:字 ...

  2. (转)两种高效过滤敏感词算法--DFA算法和AC自动机算法

    原文:https://blog.csdn.net/u013421629/article/details/83178970 一道bat面试题:快速替换10亿条标题中的5万个敏感词,有哪些解决思路? 有十 ...

  3. SpringBoot开发十五-发布帖子

    需求介绍 使用 AJAX 异步通信实现网页能够增量的更新呈现到页面上而不需要刷新整个页面. 现在基本上都是服务器返回 JSON 字符串来解析 代码实现 使用 JQuery 发送 AJAX 请求. 首先 ...

  4. web前端js过滤敏感词

    web前端js过滤敏感词 这里是用文本输入框还有文本域绑定了失去焦点事件,然后再遍历敏感词数组进行匹配和替换. var keywords=["阿扁","呵呵", ...

  5. 过滤敏感词工具类SensitiveFilter

    网上过滤敏感词工具类有的存在挺多bug,这是我自己改用的过滤敏感词工具类,目前来说没啥bug,如果有bug欢迎在评论指出 使用前缀树 Trie 实现的过滤敏感词,树节点用静态内部类表示了,都写在一个 ...

  6. STC8H开发(十四): I2C驱动RX8025T高精度实时时钟芯片

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  7. [转]Filter实现处理中文乱码,转义html标签,过滤敏感词

    原文地址:http://www.cnblogs.com/xdp-gacl/p/3952405.html 在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可 ...

  8. SpringBoot开发十九-添加评论

    需求介绍 熟悉事务管理,并且应用到添加评论的功能. 数据层:增加评论数据,修改帖子的评论数量 业务层:处理添加评论的业务,先增加评论再更新帖子的评论数量(因为用到了两个DML操作所以要用到事务管理) ...

  9. js 过滤敏感词 ,可将带有标点符号的敏感词过滤掉

    function transSensitive(content) { // var Sensitive = H.getStorage("Sensitive");//敏感词数组 va ...

随机推荐

  1. linux命令-------find命令之exec

    p.p1 { margin: 0; font: 18px "Hannotate SC"; color: rgba(4, 51, 255, 1); -webkit-text-stro ...

  2. LVM磁盘管理实战案例

    前言:这是关于centos/linux上的LVM磁盘上的扩容,缩减,磁盘类型等收集做的案例 至于ubuntu系统的磁盘扩容参考:https://www.jianshu.com/p/5dcfcec687 ...

  3. ARTS第一周

    开始进行的第一周. 1.Algorithm:每周至少做一个 leetcode 的算法题2.Review:阅读并点评至少一篇英文技术文章3.Tip:学习至少一个技术技巧4.Share:分享一篇有观点和思 ...

  4. C语言:char讲解与例子

    #include <stdio.h> main() { char bla,blb,blc;//声明或定义三个字符型变量,变量名为bla,blb,blc //字符型数据用标识符char来标识 ...

  5. CocoaPods 私有化

    一.创建所需要的代码仓库 创建 Spec 私有索引库(ZFSpec),用来存放本地spec 创建模块私有库(ZFPodProject),用来存放项目工程文件 二.私有索引库添加到本地 CocoaPod ...

  6. CF1214E Petya and Construction Set题解

    原来这就叫构造题,了 这道题的做法,我自己诌了一个形象的名字--"挂葡萄"法( 首先,"搭葡萄架":考虑到每个距离 \(d_i\) 只与 \(2i-1,2i\) ...

  7. Spring Cloud 从入门到精通(一)Nacos 服务中心初探

     什么是Nacos? Nacos是阿里巴巴开源的项目,是一个更易于帮助构建云原生应用的动态服务发现.配置管理和服务管理平台.英文全称 Dynamic Naming and Configuration ...

  8. python框架之Flask

    介绍:Flask是一个使用 Python 编写的轻量级 Web 应用框架.其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 . WSGl:Web Server Gateway ...

  9. Python自动化测试面试题-经验篇

    目录 Python自动化测试面试题-经验篇 Python自动化测试面试题-用例设计篇 Python自动化测试面试题-Linux篇 Python自动化测试面试题-MySQL篇 Python自动化测试面试 ...

  10. Django模板中变量的运算

    在django中的模板下我们知道变量使用{{xxx}}来呈现,可是当出现两个变量进行运算怎么处理那? #加法: {{value|add:value2}} #返回的结果是value+value2的值,假 ...