3.1过滤敏感词

通常不采用API,而采用前缀树 这种数据结构 来实现敏感词过滤 。
本节目的是 三步走,开发一个工具:
利用敏感词库构造前缀树
前缀树特点:
1.根节点是空的
2.除了根节点 以外的每个节点,都包含一个字符
3.从根节点 到最末级子节点 的路径上 链接起来(代码中用 布尔值判断是否为最末子节点),就是一个敏感词
4.每一层节点 不能有重复值,否则合并
如何检测敏感词呢
需要三个指针:
需要两个指针才能将单词中的敏感词标记出来 。
2指针标记 待检测敏感词的 起始位置 。若起始值满足 敏感词库,则3指针从当前位置开始向后移动 。1指针到达 敏感词库对应位置
此时2不动,3接着走
此时,发现以a开头的不是敏感词
1归位root,23节点向后移动
查到敏感词后,在中写*
【3.1过滤敏感词】最后得到:
通过代码实现:
敏感词库可以定义到文件,也可以定义到数据库 。

3.1过滤敏感词

文章插图
我们采用前者,在文件夹下新建 敏感词库-words
在util下新建工具类
首先定义内部类-前缀树
// 前缀树private class TrieNode {// 关键词结束标识private boolean isKeywordEnd = false;// 子节点(key是下级字符,value是下级节点)private Map subNodes = new HashMap<>();//subNodes初始化为空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);}}}
2.根据敏感词,初始化前缀树
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;@Componentpublic class SensitiveFilter {private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);// 替换符private static final String REPLACEMENT = "***";// 根节点private TrieNode rootNode = new TrieNode();@PostConstructpublic void init() {try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");//字节流BufferedReader reader = new BufferedReader(new InputStreamReader(is));//把字节流变为字符流new InputStreamReader(is),然后把字符流变为缓冲流new BufferedReader(new InputStreamReader(is))) {String keyword;while ((keyword = reader.readLine()) != null) {//每次读取到的值,都存到keyword变量中// 读到敏感词 。并将其添加到前缀树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);//tempNode当前节点 。getSubNode将字符挂在到子节点if (subNode == null) {//但如果子节点为空// 初始化子节点subNode = new TrieNode();tempNode.addSubNode(c, subNode);//将初始化好的子节点 挂到当前节点之下,c是当前字符}// 指向子节点,进入下一轮循环tempNode = subNode;// 设置结束标识 。一个单词的最后一个字符,需要设置结束标识if (i == keyword.length() - 1) {tempNode.setKeywordEnd(true);}}}}