首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >敏感词过滤器的实现

敏感词过滤器的实现

作者头像
全栈程序员站长
发布2022-06-30 17:43:40
发布2022-06-30 17:43:40
1.7K0
举报

大家好,又见面了,我是你们的朋友全栈君。

敏感词过滤器的实现

导包

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

代码语言:javascript
复制
<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,表示子节点。实现的代码如下。

代码语言:javascript
复制
    //前缀树
    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);
        }
    }

敏感词过滤器的实现

代码语言:javascript
复制
@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://javaforall.cn/132243.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 敏感词过滤器的实现
  • 导包
  • 敏感词文件
  • 前缀树的实现
  • 敏感词过滤器的实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档