敏感词过滤通常是指在文本中检测并替换或删除不适宜的内容。基于DFA(Deterministic Finite Automaton,确定性有限自动机)算法的敏感词过滤是一种高效的方法。DFA算法通过构建一个状态机来匹配敏感词,其核心思想是将每个敏感词转换成一个状态机,然后通过遍历文本来检测敏感词。
所以我们需要有一个自定义的敏感词库,并将其存储在一种高效的数据结构中。
适应快速定位查找的数据结构我们很容易想到HashMap,但我们的理想结构是类似底层HashMap(hash+树的结构)
所以我们给出的数据结构为:
private static final Map<Character, Map> DFA = new HashMap<>();
这样的设计方便我们进行拓展
代码+解释:
java">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;//引用DFAfor (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自动机和字典树(前缀树)等算法。