DFA,全稱 Deterministic Finite Automaton, 即確定有窮自動機(jī)。
黑馬頭條項(xiàng)目的敏感詞過濾工具類,基于DFA算法思想。
package com.heima.utils.common;
import JAVA.util.*;
public class SensitivewordUtil {
public static Map<String, Object> dictionaryMap = new HashMap<>();
/**
* 生成關(guān)鍵詞字典庫
* @param words
* @return
*/
public static void initMap(Collection<String> words) {
if (words == null) {
System.out.println("敏感詞列表不能為空");
return ;
}
// map初始長度words.size(),整個字典庫的入口字?jǐn)?shù)(小于words.size(),因?yàn)椴煌脑~可能會有相同的首字)
Map<String, Object> map = new HashMap<>(words.size());
// 遍歷過程中當(dāng)前層次的數(shù)據(jù)
Map<String, Object> curMap = null;
Iterator<String> iterator = words.iterator();
while (iterator.hasNext()) {
String word = iterator.next();
curMap = map;
int len = word.length();
for (int i =0; i < len; i++) {
// 遍歷每個詞的字
String key = String.valueOf(word.charAt(i));
// 當(dāng)前字在當(dāng)前層是否存在, 不存在則新建, 當(dāng)前層數(shù)據(jù)指向下一個節(jié)點(diǎn), 繼續(xù)判斷是否存在數(shù)據(jù)
Map<String, Object> wordMap = (Map<String, Object>) curMap.get(key);
if (wordMap == null) {
// 每個節(jié)點(diǎn)存在兩個數(shù)據(jù): 下一個節(jié)點(diǎn)和isEnd(是否結(jié)束標(biāo)志)
wordMap = new HashMap<>(2);
wordMap.put("isEnd", "0");
curMap.put(key, wordMap);
}
curMap = wordMap;
// 如果當(dāng)前字是詞的最后一個字,則將isEnd標(biāo)志置1
if (i == len -1) {
curMap.put("isEnd", "1");
}
}
}
dictionaryMap = map;
}
/**
* 搜索文本中某個文字是否匹配關(guān)鍵詞
* @param text
* @param beginIndex
* @return
*/
private static int checkWord(String text, int beginIndex) {
if (dictionaryMap == null) {
throw new RuntimeException("字典不能為空");
}
boolean isEnd = false;
int wordLength = 0;
Map<String, Object> curMap = dictionaryMap;
int len = text.length();
// 從文本的第beginIndex開始匹配
for (int i = beginIndex; i < len; i++) {
String key = String.valueOf(text.charAt(i));
// 獲取當(dāng)前key的下一個節(jié)點(diǎn)
curMap = (Map<String, Object>) curMap.get(key);
if (curMap == null) {
break;
} else {
wordLength ++;
if ("1".equals(curMap.get("isEnd"))) {
isEnd = true;
}
}
}
if (!isEnd) {
wordLength = 0;
}
return wordLength;
}
/**
* 獲取匹配的關(guān)鍵詞和命中次數(shù)
* @param text
* @return
*/
public static Map<String, Integer> matchWords(String text) {
Map<String, Integer> wordMap = new HashMap<>();
int len = text.length();
for (int i = 0; i < len; i++) {
int wordLength = checkWord(text, i);
if (wordLength > 0) {
String word = text.substring(i, i + wordLength);
// 添加關(guān)鍵詞匹配次數(shù)
if (wordMap.contAInsKey(word)) {
wordMap.put(word, wordMap.get(word) + 1);
} else {
wordMap.put(word, 1);
}
i += wordLength - 1;
}
}
return wordMap;
}
}