敏感词过滤通常是指在文本中检测并替换或删除不适宜的内容。基于DFA(Deterministic Finite Automaton,确定性有限自动机)算法的敏感词过滤是一种高效的方法。DFA算法通过构建一个状态机来匹配敏感词,其核心思想是将每个敏感词转换成一个状态机,然后通过遍历文本来检测敏感词。
所以我们需要有一个自定义的敏感词库,并将其存储在一种高效的数据结构中。
适应快速定位查找的数据结构我们很容易想到HashMap,但我们的理想结构是类似底层HashMap(hash+树的结构)
所以我们给出的数据结构为:
private static final Map<Character, Map> DFA = new HashMap<>();
这样的设计方便我们进行拓展
代码+解释:
public class SensitiveWordFilter {
private static final Map<Character, Map> DFA = new HashMap<>();
static {
// 初始化DFA状态机,这里以"敏感词"和"词"为例
initDFA("敏感");
initDFA("感词");
initDFA("啊");
}
public static void initDFA(String word) {
Map<Character, Map> currMap = DFA;//引用DFA
for (char c : word.toCharArray()) {
//判断这个词在不在我们构建的敏感词树中,如果不在我们需要为它创建
/*
* computeIfAbsent是一个Map方法,它检查当前Map是否包含指定键(这里是敏感词中的字符ch)的映射。
* 如果不存在这样的映射,它会使用提供的函数(k -> new HashMap<>())来创建一个新的Map,并将其作为该键的值。
* */
currMap = (Map<Character, Map>)currMap.computeIfAbsent(c, k -> new HashMap<>());
}
currMap.put('\0', null); // 终止符
}
//过滤敏感词
public static String filter(String str) {
StringBuilder sb = new StringBuilder();
int length = str.length();
for(int i = 0; i < length; i++){
Map<Character, Map> currMap = DFA;
char ch = str.charAt(i);
int currIndex = i;
boolean found = false;//是否发现敏感词
//当前词匹配敏感词的首字母
while(currIndex < length && currMap.containsKey(str.charAt(currIndex))){
//取出此敏感词作根的树
currMap = currMap.get(str.charAt(currIndex));
//往下匹配其余词
currIndex++;
if(currMap.containsKey('\0')) {//说明当前匹配到底了
found = true;//发现敏感词
//替换敏感词
replace(sb, i, currIndex);
//跳过已找出的敏感词,继续匹配
i = currIndex - 1;
break;
}
}
//首字母匹配上了但是最后没匹配上
if(!found && currIndex > i){
currIndex = i;
}
//说明该词不是敏感词,首字母就没匹配上
if(i == currIndex) {
sb.append(ch);
}
}
return sb.toString();
}
public static void replace(StringBuilder sb, int start, int end) {
for(int i = start; i < end; i++) {
sb.append("*");
}
}
public static void main(String[] args) {
String text = "敏感词的示例词。";
String filteredText = filter(text);
System.out.println(filteredText); // 输出: 这是一个包含***的示例***
}
}
虽然DFA算法在很多场景下表现良好,但它并不是唯一的解决方案,也不一定是所有情况下最高效的算法,还有AC自动机和字典树(前缀树)等算法。

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



