java實現敏感詞過濾(DFA算法)

小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

本文出自博客園,歡迎你們加入博客園。

相關文章
相關標籤/搜索