Java实战之敏感词过滤器

网友投稿 312 2023-01-18

Java实战之敏感词过滤器

一、导包

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

org.springframework.boot

spring-boot-starter-aop

org.springframework.boot

spring-boot-starter-thymeleaf

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-devtools

runtime

org.springframework.boot

spring-boot-starter-test

test

org.apache.commons

commons-lang3

3.9

二、敏感词文件

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

三、前缀树的实现

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

//前缀树

private class TrieNode{

//关键词结束标识

private boolean isKeywordEnd = false;

//子节点

private Map 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

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

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();

http:// }

//判断是否为符号

private boolean isSymbol(Character c){

// 0KAXHnORWx2E80~0x9FFF 是东亚文字范围

return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);

}

}

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

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();

http:// }

//判断是否为符号

private boolean isSymbol(Character c){

// 0KAXHnORWx2E80~0x9FFF 是东亚文字范围

return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);

}

}

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();

http:// }

//判断是否为符号

private boolean isSymbol(Character c){

// 0KAXHnORWx2E80~0x9FFF 是东亚文字范围

return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);

}

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java实战之城市多音字处理
下一篇:php开放api接口(php api 框架)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~