最近看到这个问题,感觉是一个不错的题目,尝试解决并记录一下:
具体问题是: 给定一个字符串,通过指定敏感词,将字符串中敏感词进行替换。
常见有三种解法:
- 暴力两重For嵌套
- KMP
- Trie树
今天尝试用敏感词构建Trie树解决问题,代码如下:
import org.apache.commons.lang3.CharUtils;
import java.util.HashMap;
import java.util.Map;
public class trie {
//敏感词构建的Trie树
private class TrieNode{
//用于标记敏感词的结尾
private boolean isEnd = false;
//下一层节点
Map<Character,TrieNode> subNodes = new HashMap<>();
//添加下一个敏感词节点
public void addSubNode(Character c, TrieNode node){
subNodes.put(c, node);
}
//获取下一个敏感词节点
public TrieNode getSubNode(Character c){
return subNodes.get(c);
}
//设置敏感词结尾
public void setEnd(boolean end){
this.isEnd = end;
}
//判断敏感词是否结尾
public boolean getIsEnd(){
return this.isEnd;
}
}
//替换词
private static final String DEFAULT_REPLACEMENT = "***";
//初始化Trie树
private TrieNode root;
public trie(){
root = new TrieNode();
}
//识别特殊符号
private boolean isSymbol(Character c){
int ic = (int) c;
//非ASCII编码且不在0x2E80-0x9FFF 东亚文字范围内
return !CharUtils.isAsciiAlphanumeric(c) && (ic < 0x2E80 || ic > 0x9FFF);
}
//将敏感词添加到字典树中
public void addWord(String text){
//trim() 函数移除字符串两侧的空白字符或其他预定义字符
if(text == null || text.trim().equals("")){
return;
}
TrieNode curNode = root;
int length = text.length();
for(int index = 0; index < length; ++index){
Character c = text.charAt(index);
//过滤敏感词中的特殊字符
if(isSymbol(c)){
//跳出本次循环
continue;
}
TrieNode subNode = curNode.getSubNode(c);
//添加子节点
if(subNode == null){
subNode = new TrieNode();
curNode.addSubNode(c, subNode);
}
curNode = subNode;
//设置敏感词标识
if(index == length - 1){
curNode.setEnd(true);
}
}
}
//过滤敏感词
public String filter(String text){
if(text == null || text.trim().equals("")){
return text;
}
String replacement = DEFAULT_REPLACEMENT;
//非线程安全
StringBuilder result = new StringBuilder();
TrieNode curNode = root;
int start = 0;//确定过滤词的起点
int end = 0;//过滤词的终点
while(end < text.length()){
Character c = text.charAt(end);
//判断特殊符号
if(isSymbol(c)){
//进来代表是特殊符号:
if(curNode == root){
//没匹配到敏感词,就后移开始位置和结束位置(因为不管是否匹配到都要移动结束位置,所以写在下面),把这个符号加入结果中
result.append(c);
++start;
}
//curNode不是root,代表正在匹配敏感词的过程中。略过这个符号,end后移,退出此次循环,继续下轮判断。
++end;
continue;
}
curNode = curNode.getSubNode(c);
//代表敏感词Trie树中不存在该字符开头的敏感词
if(curNode == null){
//以start开始的字符串不是敏感词
result.append(text.charAt(start));
//end字符串和start字符串都跳到下一个字符
end = start + 1;
start = end;
//敏感词Trie树回到根节点重新等待开始
curNode = root;
}else if(curNode.getIsEnd()){
//curNode.getIsEnd()=True 代表该敏感词已经遍历到尾部 需要对其进行替换
result.append(replacement);
end = end + 1;
start = end;
//敏感词Trie树回到根节点重新等待开始
curNode = root;
}else{
//curNode.getIsEnd()=False 代表该敏感词已经遍历到尾部 需要对其进行替换
++end;
}
}
//??
result.append(text.substring(start));
return result.toString();
}
//测试方法是否成功
public static void main(String[] args){
//构建敏感词树并添加敏感词
trie myTrie = new trie();
myTrie.addWord("de");
myTrie.addWord("bca");
myTrie.addWord("色情内容");
//过滤文本中的敏感词
String ans = myTrie.filter("ab cad ef");
System.out.println(ans);
String ans1 = myTrie.filter("以下是:色情 内容");
String ans2 = myTrie.filter("以下是:色情·内容");
System.out.println(ans1);
System.out.println(ans2);
}
}
输出内容:

该博客介绍了一种使用Trie树来过滤敏感词的方法,通过构建Trie树,可以高效地查找并替换字符串中的敏感词汇。博主详细展示了如何在Java中实现这一过程,包括Trie树节点的定义、添加敏感词到树中以及过滤文本的步骤。测试案例显示了方法的有效性。

被折叠的 条评论
为什么被折叠?



