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