小Alan在最近的開發中遇到了敏感詞過濾,便去網上查閱了不少敏感詞過濾的資料,在這裏也和你們分享一下本身的理解。前端
敏感詞過濾應該是不用給你們過多的解釋吧?講白了就是你在項目中輸入某些字(好比輸入xxoo相關的文字時)時要能檢java
測出來,不少項目中都會有一個敏感詞管理模塊,在敏感詞管理模塊中你能夠加入敏感詞,而後根據加入的敏感詞去過濾輸web
入內容中的敏感詞並進行相應的處理,要麼提示,要麼高亮顯示,要麼直接替換成其它的文字或者符號代替。 算法
敏感詞過濾的作法有不少,我簡單描述我如今理解的幾種:數據庫
①查詢數據庫當中的敏感詞,循環每個敏感詞,而後去輸入的文本中從頭至尾搜索一遍,看是否存在此敏感詞,有則作相app
應的處理,這種方式講白了就是找到一個處理一個。ide
優勢:so easy。用java代碼實現基本沒什麼難度。工具
缺點:這效率讓我心中奔過十萬匹草泥馬,並且匹配的是否是有些蛋疼,若是是英文時你會發現一個很無語的事情,好比英文優化
a是敏感詞,那我若是是一篇英文文檔,那程序它妹的得處理多少次敏感詞?誰能告訴我?spa
②傳說中的DFA算法(有窮自動機),也正是我要給你們分享的,畢竟感受比較通用,算法的原理但願你們可以本身去網上查查
資料,這裏就不詳細說明了。
優勢:至少比上面那sb效率高點。
缺點:對於學過算法的應該不難,對於沒學過算法的用起來也不難,就是理解起來有點gg疼,匹配效率也不高,比較耗費內存,
敏感詞越多,內存佔用的就越大。
③第三種在這裏要特別說明一下,那就是你本身去寫一個算法吧,或者在現有的算法的基礎上去優化,這也是小Alan追求的至
高境界之一,若是哪位淫兄有本身的想法必定別忘了小Alan,能夠加小Alan的QQ:810104041教小Alan兩招耍耍。
那麼,傳說中的DFA算法是怎麼實現的呢?
第一步:敏感詞庫初始化(將敏感詞用DFA算法的原理封裝到敏感詞庫中,敏感詞庫採用HashMap保存),代碼以下:
1 package com.cfwx.rox.web.sysmgr.util; 2 3 import java.util.HashMap; 4 import java.util.HashSet; 5 import java.util.Iterator; 6 import java.util.List; 7 import java.util.Map; 8 import java.util.Set; 9 10 import com.cfwx.rox.web.common.model.entity.SensitiveWord; 11 12 /** 13 * 敏感詞庫初始化 14 * 15 * @author AlanLee 16 * 17 */ 18 public class SensitiveWordInit 19 { 20 /** 21 * 敏感詞庫 22 */ 23 public HashMap sensitiveWordMap; 24 25 /** 26 * 初始化敏感詞 27 * 28 * @return 29 */ 30 public Map initKeyWord(List<SensitiveWord> sensitiveWords) 31 { 32 try 33 { 34 // 從敏感詞集合對象中取出敏感詞並封裝到Set集合中 35 Set<String> keyWordSet = new HashSet<String>(); 36 for (SensitiveWord s : sensitiveWords) 37 { 38 keyWordSet.add(s.getContent().trim()); 39 } 40 // 將敏感詞庫加入到HashMap中 41 addSensitiveWordToHashMap(keyWordSet); 42 } 43 catch (Exception e) 44 { 45 e.printStackTrace(); 46 } 47 return sensitiveWordMap; 48 } 49 50 /** 51 * 封裝敏感詞庫 52 * 53 * @param keyWordSet 54 */ 55 @SuppressWarnings("rawtypes") 56 private void addSensitiveWordToHashMap(Set<String> keyWordSet) 57 { 58 // 初始化HashMap對象並控制容器的大小 59 sensitiveWordMap = new HashMap(keyWordSet.size()); 60 // 敏感詞 61 String key = null; 62 // 用來按照相應的格式保存敏感詞庫數據 63 Map nowMap = null; 64 // 用來輔助構建敏感詞庫 65 Map<String, String> newWorMap = null; 66 // 使用一個迭代器來循環敏感詞集合 67 Iterator<String> iterator = keyWordSet.iterator(); 68 while (iterator.hasNext()) 69 { 70 key = iterator.next(); 71 // 等於敏感詞庫,HashMap對象在內存中佔用的是同一個地址,因此此nowMap對象的變化,sensitiveWordMap對象也會跟着改變 72 nowMap = sensitiveWordMap; 73 for (int i = 0; i < key.length(); i++) 74 { 75 // 截取敏感詞當中的字,在敏感詞庫中字爲HashMap對象的Key鍵值 76 char keyChar = key.charAt(i); 77 78 // 判斷這個字是否存在於敏感詞庫中 79 Object wordMap = nowMap.get(keyChar); 80 if (wordMap != null) 81 { 82 nowMap = (Map) wordMap; 83 } 84 else 85 { 86 newWorMap = new HashMap<String, String>(); 87 newWorMap.put("isEnd", "0"); 88 nowMap.put(keyChar, newWorMap); 89 nowMap = newWorMap; 90 } 91 92 // 若是該字是當前敏感詞的最後一個字,則標識爲結尾字 93 if (i == key.length() - 1) 94 { 95 nowMap.put("isEnd", "1"); 96 } 97 System.out.println("封裝敏感詞庫過程:"+sensitiveWordMap); 98 } 99 System.out.println("查看敏感詞庫數據:" + sensitiveWordMap); 100 } 101 } 102 }
第二步:寫一個敏感詞過濾工具類,裏面能夠寫上本身須要的方法,代碼以下:
1 package com.cfwx.rox.web.sysmgr.util; 2 3 import java.util.HashSet; 4 import java.util.Iterator; 5 import java.util.Map; 6 import java.util.Set; 7 8 /** 9 * 敏感詞過濾工具類 10 * 11 * @author AlanLee 12 * 13 */ 14 public class SensitivewordEngine 15 { 16 /** 17 * 敏感詞庫 18 */ 19 public static Map sensitiveWordMap = null; 20 21 /** 22 * 只過濾最小敏感詞 23 */ 24 public static int minMatchTYpe = 1; 25 26 /** 27 * 過濾全部敏感詞 28 */ 29 public static int maxMatchType = 2; 30 31 /** 32 * 敏感詞庫敏感詞數量 33 * 34 * @return 35 */ 36 public static int getWordSize() 37 { 38 if (SensitivewordEngine.sensitiveWordMap == null) 39 { 40 return 0; 41 } 42 return SensitivewordEngine.sensitiveWordMap.size(); 43 } 44 45 /** 46 * 是否包含敏感詞 47 * 48 * @param txt 49 * @param matchType 50 * @return 51 */ 52 public static boolean isContaintSensitiveWord(String txt, int matchType) 53 { 54 boolean flag = false; 55 for (int i = 0; i < txt.length(); i++) 56 { 57 int matchFlag = checkSensitiveWord(txt, i, matchType); 58 if (matchFlag > 0) 59 { 60 flag = true; 61 } 62 } 63 return flag; 64 } 65 66 /** 67 * 獲取敏感詞內容 68 * 69 * @param txt 70 * @param matchType 71 * @return 敏感詞內容 72 */ 73 public static Set<String> getSensitiveWord(String txt, int matchType) 74 { 75 Set<String> sensitiveWordList = new HashSet<String>(); 76 77 for (int i = 0; i < txt.length(); i++) 78 { 79 int length = checkSensitiveWord(txt, i, matchType); 80 if (length > 0) 81 { 82 // 將檢測出的敏感詞保存到集合中 83 sensitiveWordList.add(txt.substring(i, i + length)); 84 i = i + length - 1; 85 } 86 } 87 88 return sensitiveWordList; 89 } 90 91 /** 92 * 替換敏感詞 93 * 94 * @param txt 95 * @param matchType 96 * @param replaceChar 97 * @return 98 */ 99 public static String replaceSensitiveWord(String txt, int matchType, String replaceChar) 100 { 101 String resultTxt = txt; 102 Set<String> set = getSensitiveWord(txt, matchType); 103 Iterator<String> iterator = set.iterator(); 104 String word = null; 105 String replaceString = null; 106 while (iterator.hasNext()) 107 { 108 word = iterator.next(); 109 replaceString = getReplaceChars(replaceChar, word.length()); 110 resultTxt = resultTxt.replaceAll(word, replaceString); 111 } 112 113 return resultTxt; 114 } 115 116 /** 117 * 替換敏感詞內容 118 * 119 * @param replaceChar 120 * @param length 121 * @return 122 */ 123 private static String getReplaceChars(String replaceChar, int length) 124 { 125 String resultReplace = replaceChar; 126 for (int i = 1; i < length; i++) 127 { 128 resultReplace += replaceChar; 129 } 130 131 return resultReplace; 132 } 133 134 /** 135 * 檢查敏感詞數量 136 * 137 * @param txt 138 * @param beginIndex 139 * @param matchType 140 * @return 141 */ 142 public static int checkSensitiveWord(String txt, int beginIndex, int matchType) 143 { 144 boolean flag = false; 145 // 記錄敏感詞數量 146 int matchFlag = 0; 147 char word = 0; 148 Map nowMap = SensitivewordEngine.sensitiveWordMap; 149 for (int i = beginIndex; i < txt.length(); i++) 150 { 151 word = txt.charAt(i); 152 // 判斷該字是否存在於敏感詞庫中 153 nowMap = (Map) nowMap.get(word); 154 if (nowMap != null) 155 { 156 matchFlag++; 157 // 判斷是不是敏感詞的結尾字,若是是結尾字則判斷是否繼續檢測 158 if ("1".equals(nowMap.get("isEnd"))) 159 { 160 flag = true; 161 // 判斷過濾類型,若是是小過濾則跳出循環,不然繼續循環 162 if (SensitivewordEngine.minMatchTYpe == matchType) 163 { 164 break; 165 } 166 } 167 } 168 else 169 { 170 break; 171 } 172 } 173 if (!flag) 174 { 175 matchFlag = 0; 176 } 177 return matchFlag; 178 } 179 180 }
第三步:一切都準備就緒,固然是查詢好數據庫當中的敏感詞,而且開始過濾咯,代碼以下:
1 @SuppressWarnings("rawtypes") 2 @Override 3 public Set<String> sensitiveWordFiltering(String text) 4 { 5 // 初始化敏感詞庫對象 6 SensitiveWordInit sensitiveWordInit = new SensitiveWordInit(); 7 // 從數據庫中獲取敏感詞對象集合(調用的方法來自Dao層,此方法是service層的實現類) 8 List<SensitiveWord> sensitiveWords = sensitiveWordDao.getSensitiveWordListAll(); 9 // 構建敏感詞庫 10 Map sensitiveWordMap = sensitiveWordInit.initKeyWord(sensitiveWords); 11 // 傳入SensitivewordEngine類中的敏感詞庫 12 SensitivewordEngine.sensitiveWordMap = sensitiveWordMap; 13 // 獲得敏感詞有哪些,傳入2表示獲取全部敏感詞 14 Set<String> set = SensitivewordEngine.getSensitiveWord(text, 2); 15 return set; 16 }
最後一步:在Controller層寫一個方法給前端請求,前端獲取到須要的數據並進行相應的處理,代碼以下:
1 /** 2 * 敏感詞過濾 3 * 4 * @param text 5 * @return 6 */ 7 @RequestMapping(value = "/word/filter") 8 @ResponseBody 9 public RespVo sensitiveWordFiltering(String text) 10 { 11 RespVo respVo = new RespVo(); 12 try 13 { 14 Set<String> set = sensitiveWordService.sensitiveWordFiltering(text); 15 respVo.setResult(set); 16 } 17 catch (Exception e) 18 { 19 throw new RoxException("過濾敏感詞出錯,請聯繫維護人員"); 20 } 21 22 return respVo; 23 }
小Alan在代碼中寫了很多的註釋,但願你們可以動動本身的腦筋好好的理解一下。
可愛博主:AlanLee
博客地址:http://www.cnblogs.com/AlanLee
本文出自博客園,歡迎你們加入博客園。