Java实战之敏感词过滤器

一、导包

本文的敏感词过滤器用在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,里面填入需要过滤的敏感词信息。


三、前缀树的实现

前缀树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);
    }
}

到此这篇关于Java实战之敏感词过滤器的文章就介绍到这了,更多相关Java敏感词过滤器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java实现DFA算法对敏感词、广告词过滤功能示例

    一.前言 开发中经常要处理用户一些文字的提交,所以涉及到了敏感词过滤的功能,参考资料中DFA有穷状态机算法的实现,创建有向图.完成了对敏感词.广告词的过滤,而且效率较好,所以分享一下. 具体实现: 1.匹配大小写过滤  2.匹配全角半角过滤  3.匹配过滤停顿词过滤.  4.敏感词重复词过滤. 例如: 支持如下类型类型过滤检测: fuck 全小写 FuCk 大小写 fuck全角半角 f!!!u&c ###k 停顿词 fffuuuucccckkk 重复词 敏感词过滤的做法有很多,我简单描述我现在理

  • 布隆过滤器的原理以及java 简单实现

    一.布隆过滤器 布隆过滤器(Bloom Filter)是1970年由布隆提出的.它实际上是一个很长的二进制向量和一系列随机映射函数.布隆过滤器可以用于检索一个元素是否在一个集合中.它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难. 如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定.链表.树.散列表(又叫哈希表,Hash table)等等数据结构都是这种思路.但是随着集合中元素的增加,我们需要的存储空间越来越大.同时检索

  • java过滤器中Filter的ChainFilter过滤链

    1.什么是过滤器? 在客户端到服务器的过程中,当发送请求时,如果有不符合的信息将会被filter进行拦截,如果符合则会进行放行,在服务器给客户端响应时也会进行判断 如果有不符合的信息将会被filter进行拦截,如果符合则会进行放行. OOP:Java面向对象编程,抽象.封装.继承.多态. AOP:面向切面编程,过滤器就是一个面向切面的编程思想. AOP是sun公司srvlet2.3版本之后推出的新功能,在2.3之前的版本没有该功能,定义一个过滤器需要实现(implement)Filter接口,这

  • java利用DFA算法实现敏感词过滤功能

    前言 敏感词过滤应该是不用给大家过多的解释吧?讲白了就是你在项目中输入某些字(比如输入xxoo相关的文字时)时要能检 测出来,很多项目中都会有一个敏感词管理模块,在敏感词管理模块中你可以加入敏感词,然后根据加入的敏感词去过滤输 入内容中的敏感词并进行相应的处理,要么提示,要么高亮显示,要么直接替换成其它的文字或者符号代替. 敏感词过滤的做法有很多,我简单描述我现在理解的几种: ①查询数据库当中的敏感词,循环每一个敏感词,然后去输入的文本中从头到尾搜索一遍,看是否存在此敏感词,有则做相 应的处理,

  • JavaEE Filter敏感词过滤的方法实例详解

    我们在聊天的时候的或者留言的时候,有部分词是不允许发表出来.我们可以采用过滤器实现这个功能. 我们只是简单利用过滤器实现这个过滤的功能,有些地方没写的很全 前台代码: <body> <form action="<c:url value='/WordServlet'/>" method="post"> 姓名:<input type="text" name="name"/><b

  • Java使用过滤器防止SQL注入XSS脚本注入的实现

    前几天有个客户在系统上写了一段html语句,打开页面就显示一张炒鸡大的图片,影响美观.后来仔细想想,幸亏注入的仅仅是html语句,知道严重性后,马上开始一番系统安全配置. 一. 定义过滤器 package com.cn.unit.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; i

  • Java使用Gateway自定义负载均衡过滤器

    背景 最近项目中需要上传视频文件,由于视频文件可能会比较大,但是我们应用服务器tomcat设置单次只支持的100M,因此决定开发一个分片上传接口. 把大文件分成若干个小文件上传.所有文件上传完成后通过唯一标示进行合并文件. 我们的开发人员很快完成了开发,并在单元测试中表现无误.上传代码到测试环境,喔嚯!!!出错了. 经过一段时间的辛苦排查终于发现问题,测试环境多实例,分片上传的接口会被路由到不同的实例,导致上传后的分片文件在不同的机器,那么也就无法被合并. 知道了原因就好解决,经过一系列的过程最

  • 使用java8 API遍历过滤文件目录及子目录和隐藏文件示例详解

    1. 使用Files.list()迭代目录及其子目录文件 Files.list()可以迭代目录及其子目录文件 Files.list(Paths.get(".")) //当前目录 .forEach(System.out::println); 输出: .\filename1.txt .\directory1 .\filename2.txt .\Employee.java 2. 使用 filter表达式过滤文件 过滤器函数引用,isRegularFile表示普通文件 Files.list(P

  • 聊聊java 过滤器、监听器、拦截器的区别(终结篇)

    过滤器.监听器.拦截器概念 概念 1.servlet:servlet是一种运行服务器端的java应用程序,具有独立于平台和协议的特性, 可以动态生成web页面它工作在客户端请求与服务器响应的中间层: 2.filter:filter是一个可以复用的代码片段,可以用来转换HTTP请求,响应和头信息. 它不能产生一个请求或者响应,它只是修改对某一资源的请求或者响应: 3.listener:监听器,通过listener可以坚挺web服务器中某一执行动作,并根据其要求作出相应的响应. 就是在applica

  • Java实现敏感词过滤实例

    敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来一看,整个过程如下:读取敏感词库.如果HashSet集合中,获取页面上传文字,然后进行匹配.我就想这个过程肯定是非常慢的.对于他这个没有接触的人来说我想也只能想到这个,更高级点就是正则表达式.但是非常遗憾,这两种方法都是不可行的.当然,在我意识里没有我也没有认知到那个算法可以解决问题,但是Googl

随机推荐