Java实战之敏感词过滤器

作者:鱼子酱冲鸭 时间:2022-01-18 10:32:03 

一、导包

本文的敏感词过滤器用在SpringBoot项目中,因此,首先需要在pom.xml文件中导入如下依赖


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>

二、敏感词文件

在resources目录下,创建sensitive-word.txt,里面填入需要过滤的敏感词信息。

Java实战之敏感词过滤器
Java实战之敏感词过滤器

三、前缀树的实现

前缀树TrieNode以一个空节点为头结点,每个节点下包含若干子节点,不同节点代表不同字符。TrieNode 由两部分组成,首先是一个boolean变量,表示该结点是否为一个关键词的终结点。其次是该结点的子节点集合,在本文中,用HashMap存储子节点,key存储结点代表的字符,类型为Character,value为TrieNode,表示子节点。实现的代码如下。


//前缀树
   private class TrieNode{
       //关键词结束标识
       private boolean isKeywordEnd = false;

//子节点
       private Map<Character,TrieNode> subNodes = new HashMap<>();

//isKeywordEnd的get、set方法
       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);
       }
   }

四、敏感词过滤器的实现


@Component
public class SensitiveFilter {
   // 替换符
   private static final String REPLACEMENT = "***";

//根节点
   private TrieNode rootNode = new TrieNode();

//bean的初始化方法,服务一启动,容器自动给bean执行此方法完成初始化
   //此方法的目的是读取敏感词文件,构建敏感词前缀树
   @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));
               //指针2和指针3共同指向指针2的下一个位置
               position = ++begin;
               //指针1重新指向根节点
               tempNode = rootNode;
           }else if(tempNode.isKeywordEnd()){
               //发现敏感词,将begin~position字符串替换
               sb.append(REPLACEMENT);
               //进入下一个位置
               begin = ++position;
               //指针1重新指向根节点
               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);
   }
}

来源:https://blog.csdn.net/qq_34905438/article/details/116168958

标签:Java,敏感词,过滤器
0
投稿

猜你喜欢

  • SSM如何实现在Controller中添加事务管理

    2023-11-29 07:23:18
  • Android下拉列表spinner的实例代码

    2023-07-31 20:39:47
  • 解决Java中properties文件编码问题

    2022-07-21 14:09:06
  • 浅谈Spring Boot 开发REST接口最佳实践

    2021-10-08 12:24:35
  • Spring @Profile注解详解

    2023-04-20 06:26:16
  • Java Spring AOP源码解析之事务实现原理

    2023-09-10 02:39:46
  • SSH原理及两种登录方法图文详解

    2023-11-14 11:10:53
  • Java实现FTP上传与下载功能

    2021-09-22 18:28:51
  • 从零实现一个简单的Spring Bean容器的代码案例

    2022-07-24 11:42:16
  • java中sdk与jdk的区别详细解析

    2023-11-25 03:37:14
  • java中使用zxing批量生成二维码立牌

    2021-12-31 04:31:03
  • 解决SpringBoot webSocket 资源无法加载、tomcat启动报错的问题

    2021-07-28 05:06:42
  • 详解C# 泛型中的数据类型判定与转换

    2023-05-03 08:08:36
  • Jmeter分布式压力测试实现过程详解

    2022-03-23 21:32:44
  • SpringBoot程序的打包与运行的实现

    2023-11-29 15:51:27
  • java数据结构与算法数组模拟队列示例详解

    2021-07-23 16:50:24
  • Java事件处理机制和适配器全面解析

    2021-10-23 04:19:32
  • java数据结构和算法中哈希表知识点详解

    2023-08-05 08:28:11
  • Java利用移位运算将int型分解成四个byte型的方法

    2023-11-09 08:25:00
  • Java反射通过Getter方法获取对象VO的属性值过程解析

    2023-04-11 06:11:33
  • asp之家 软件编程 m.aspxhome.com