每一個app的評論(或提問等)功能都會作敏感詞過濾。
#1.常規作法html
/** * flag:0(不是敏感詞) 1(敏感詞) */ public int checkWord() { int flag = 0; String content = "用戶評論的內容"; java.util.List<String> list = new ArrayList<>(); //從數據庫取出敏感詞彙列表 list.add("習dd"); list.add("彭mm"); list.add("網絡流行語"); for (int i = 0; i < list.size(); i++) { if (content.contains(list.get(i))) { flag = 1; break; } } return flag; }
當數據量很大的時候,如上的方法執行效率特別慢,所以須要找改進的方法,以下有一篇文章寫的不錯
http://www.cnblogs.com/chenssy/p/3751221.html#2966041
#2.改進方法
將敏感詞加入到HashMap中,構建DFA算法模型java
public class SensitiveWordInit { /** * @Description: 初始化敏感詞庫,將敏感詞加入到HashMap中,構建DFA算法模型 * @param list:從數據庫獲取到的敏感詞彙列表 * @return 敏感詞彙HashMap * 備註:原做者的入參是Set<String>,我改爲了List. * 改完後才發現做者的用心,Set的效率比List高 */ public HashMap getSensitiveWordToHashMap(List<String> list){ //敏感詞彙map HashMap sensitiveWordMap = new HashMap<>(); //關鍵字 String key = ""; //轉換map Map tempMap = null; //給臨時map賦值 Map newMap = null; //迭代器 Iterator<String> it = list.iterator(); while (it.hasNext()) { //取出關鍵詞 key = it.next(); //這裏給輸出map賦值 tempMap = sensitiveWordMap; //拆分關鍵詞,存入map for (int i = 0; i < key.length(); i++) { //因爲key是字符串型,因此裏面存放的是字符型,所以存在以下取法 //備註:其實這裏能夠將key轉成array,用array[i]取仍是同樣 char keyChar = key.charAt(i); //從轉換map裏面取出單個"關鍵字",多個關鍵字組成關鍵詞 //備註:這裏可使用String類型來接收 Object tmpKey = tempMap.get(keyChar); //若是tmpKey裏面存在該key,直接賦值 if (tmpKey != null) { tempMap = (Map)tmpKey; }else { /** * 若是不存在該key,則添加進去 */ //新構建一個map,將isEnd設值0,由於它不是最後一個 newMap = new HashMap<>(); //不是最後一個 newMap.put("isEnd", 0); //將該key添加到tempMap,其實是添加到sensitiveWordMap中 //這裏涉及到一個地址引用的知識點 tempMap.put(keyChar, newMap); //從新使tempMap指向newMap tempMap = newMap; } //最後一個 if(i == key.length() - 1){ tempMap.put("isEnd", "1"); } } } //返回敏感詞彙map return sensitiveWordMap; } }
敏感詞彙過濾類算法
/** * 敏感詞彙過濾類 * 包含三個主要方法 * 1.isContaintSensitiveWord,判斷輸入的內容是否是包含敏感詞彙 * 2.getSensitiveWord,獲取輸入內容的敏感詞 * 3.replaceSensitiveWord,替換敏感詞彙字符 */ public class SensitiveWordFilter { //敏感詞彙map private HashMap sensitiveWordMap; //最小匹配規則 //一旦匹配到,不繼續匹配,直接返回 private static int minMatchTYpe = 1; //最大匹配規則 //匹配全部的 private static int maxMatchType = 2; //關鍵詞聚集合 public List<String> list = new ArrayList<>(); /** * 構造函數,初始化敏感詞彙庫 * @param list */ public SensitiveWordFilter(List<String> list) { sensitiveWordMap = new SensitiveWordInit().getSensitiveWordToHashMap(list); } /** * 判斷輸入的內容是否是包含敏感詞彙 * @param content:輸入的內容 * @param matchType:匹配規則 * @return true or false */ public boolean isContaintSensitiveWord(String content,int matchType){ boolean flag = false; for (int i = 0; i < content.length(); i++) { //循環匹配 int matchFlag = CheckSensitiveWord(content, i, matchType); //大於0存在,返回true if(matchFlag > 0){ flag = true; } } return flag; } /** * 獲取輸入內容的敏感詞 * @param content:輸入內容 * @param matchType:匹配類型 * @return 匹配到的敏感詞列表 */ public List<String> getSensitiveWord(String content,int matchType){ List<String> sensitiveWordList = new ArrayList<>(); //判斷是否存在敏感詞彙,不存在爲0 int length = 0; for (int i = 0; i < content.length(); i++) { //判斷是否包含敏感詞彙 length = CheckSensitiveWord(content, i, matchType); //若是存在 if (length > 0) { //截取輸入內容的i到i+length sensitiveWordList.add(content.substring(i, i+length)); //減1的緣由,是由於for會自增 /** * 舉例:假設i從0開始,length=5,則匹配了0~4共5個字符 * 所以,下一次匹配時,i應該從5開始 * 注意:這一次匹配完了以後,會執行i++,所以i++的值應該是5 * 因此這裏須要將i的值設成0+5-1=4 * 這一次執行完了後,i的值變成5 */ i = i + length - 1; } } return sensitiveWordList; } /** * 替換敏感詞彙字符 * @param content:輸入的內容 * @param matchType:匹配規則 * @param replaceChar:替換字符,例如:* * @return 輸入字符串,敏感詞彙被替換成* */ public String replaceSensitiveWord(String content,int matchType,String replaceChar){ String resultTxt = content; //獲取全部的敏感詞彙 List<String> replaceSensitiveWordList = getSensitiveWord(content, matchType); //臨時變量 String word = null; //替換字符串 String replaceString = null; //迭代器 Iterator<String> it = replaceSensitiveWordList.iterator(); while (it.hasNext()) { //敏感詞彙(多個字符,假設5個字符) word = it.next(); //這是替換後的字符(假設5個) replaceString = getReplaceChars(replaceChar, word.length()); //替換後的字符串 resultTxt = resultTxt.replaceAll(word, replaceString); } return resultTxt; } /** * 獲取替換字符串 * @param replaceChar:替換成什麼字符,例如:* * @param length:須要將幾個字符替換成* * @return 多少個* */ private String getReplaceChars(String replaceChar,int length){ String resultReplace = replaceChar; for(int i = 1 ; i < length ; i++){ resultReplace += replaceChar; } return resultReplace; } /** * 檢查輸入內容是否包含敏感詞彙 * @param content:輸入內容 * @param beginIndex:匹配位置 * @param matchType:匹配規則 * @return true or false */ public int CheckSensitiveWord(String content,int beginIndex,int matchType){ //敏感詞彙結束標識符,默認爲沒有匹配到 boolean flag = false; //匹配到敏感詞彙的次數 int matchFlag = 0; //臨時變量 char word = 0; Map tmpMap = sensitiveWordMap; for (int i = beginIndex; i < content.length(); i++) { //取出輸入內容的字符 word = content.charAt(i); //獲取key tmpMap = (Map) tmpMap.get(word); //若是存在 if (tmpMap != null) { //匹配標識加1 matchFlag++; //匹配到了最後,結束循環,返回匹配數 if ("1".equals(tmpMap.get("isEnd"))) { //結束標誌位爲true flag = true; //最小規則,退出for循環;最大規則,繼續for循環 if (SensitiveWordFilter.minMatchTYpe == matchType) { break; } } }else { //不存在,直接退出for循環 break; } } //詞至少由兩個字符組成 //1.僅僅匹配到單個字符,它不能構成詞,所以匹配失敗 //2.flag=false,說明匹配失敗 if (matchFlag < 2 || !flag) { matchFlag = 0; } return matchFlag; } //測試 public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("張三"); list.add("李四"); list.add("王五"); list.add("趙六"); SensitiveWordFilter swf = new SensitiveWordFilter(list); System.out.println("敏感詞的數量:" + swf.sensitiveWordMap.size()); //輸入字符串 String content = "張三丰李四毛王五怪"; //測試1:匹配輸出全部的關鍵詞(最小匹配規則) List<String> list2 = swf.getSensitiveWord(content, 1); System.out.println(list2); //測試2:isContaintSensitiveWord boolean exite = swf.isContaintSensitiveWord(content, 1); System.out.println(exite); //測試3:將敏感詞彙替換成* String replaceString = swf.replaceSensitiveWord(content, 1, "*"); System.out.println(replaceString); } }
測試結果數據庫
敏感詞的數量:4 [張三, 李四, 王五] true **豐**毛**怪