您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“SpringBoot如何實(shí)現(xiàn)過濾敏感詞”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
過濾敏感詞
1. 創(chuàng)建一個(gè)儲存要過濾的敏感詞的文本文件
首先創(chuàng)建一個(gè)文本文件儲存要過濾的敏感詞
在下面的工具類中我們會讀取這個(gè)文本文件,這里提前給出
@PostConstruct // 這個(gè)注解表示當(dāng)容器實(shí)例化這個(gè)bean(服務(wù)啟動的時(shí)候)之后在調(diào)用構(gòu)造器之后這個(gè)方法會自動的調(diào)用 public void init(){ try( // 讀取寫有“敏感詞”的文件,getClass表示從程序編譯之后的target/classes讀配置文件,讀之后是字節(jié)流 // java7語法,在這里的句子最后會自動執(zhí)行close語句 InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt"); // 字節(jié)流 -> 字符流 -> 緩沖流 BufferedReader reader = new BufferedReader(new InputStreamReader(is)); ) { String keyword; // 從文件中一行一行讀 while ((keyword = reader.readLine()) != null){ // 添加到前綴樹 this.addKeyword(keyword); } } catch (IOException e) { logger.error("加載敏感詞文件失敗: " + e.getMessage()); } }
2. 開發(fā)過濾敏感詞的工具類
開發(fā)過濾敏感詞組件
為了方便以后復(fù)用,我們把過濾敏感詞寫成一個(gè)工具類SensitiveFilter。
@Component public class SensitiveFilter { private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class); // 當(dāng)檢測到敏感詞后我們要把敏感詞替換成什么符號 private static final String REPLACEMENT = "***"; // 根節(jié)點(diǎn) private TrieNode rootNode = new TrieNode(); @PostConstruct // 這個(gè)注解表示當(dāng)容器實(shí)例化這個(gè)bean(服務(wù)啟動的時(shí)候)之后在調(diào)用構(gòu)造器之后這個(gè)方法會自動的調(diào)用 public void init(){ try( // 讀取寫有“敏感詞”的文件,getClass表示從程序編譯之后的target/classes讀配置文件,讀之后是字節(jié)流 // java7語法,在這里的句子最后會自動執(zhí)行close語句 InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt"); // 字節(jié)流 -> 字符流 -> 緩沖流 BufferedReader reader = new BufferedReader(new InputStreamReader(is)); ) { String keyword; // 從文件中一行一行讀 while ((keyword = reader.readLine()) != null){ // 添加到前綴樹 this.addKeyword(keyword); } } catch (IOException e) { logger.error("加載敏感詞文件失敗: " + e.getMessage()); } } // 將一個(gè)敏感詞添加到前綴樹中 private void addKeyword(String keyword){ // 首先默認(rèn)指向根 TrieNode tempNode = rootNode; for (int i = 0; i < keyword.length(); i++) { char c = keyword.charAt(i); TrieNode subNode = tempNode.getSubNode(c); if(subNode == null){ // subNode為空,初始化子節(jié)點(diǎn);subNode不為空,直接用就可以了 subNode = new TrieNode(); tempNode.addSubNode(c, subNode); } // 指針指向子節(jié)點(diǎn),進(jìn)入下一輪循環(huán) tempNode = subNode; } // 最后要設(shè)置結(jié)束標(biāo)識 tempNode.setKeywordEnd(true); } /** * 過濾敏感詞 * @param text 待過濾的文本 * @return 過濾后的文本 */ public String filter(String text){ if(StringUtils.isBlank(text)){ // 待過濾的文本為空,直接返回null return null; } // 指針1,指向樹 TrieNode tempNode = rootNode; // 指針2,指向正在檢測的字符串段的首 int begin = 0; // 指針3,指向正在檢測的字符串段的尾 int position = 0; // 儲存過濾后的文本 StringBuilder sb = new StringBuilder(); while (begin < text.length()){ char c = text.charAt(position); // 跳過符號,比如 “開票”是敏感詞 #開#票# 這個(gè)字符串中間的 '#' 應(yīng)該跳過 if(isSymbol(c)){ // 是特殊字符 // 若指針1處于根節(jié)點(diǎn),將此符號計(jì)入結(jié)果,指針2、3向右走一步 if(tempNode == rootNode){ sb.append(c); begin++; } // 無論符號在開頭或中間,指針3都向下走一步 position++; // 符號處理完,進(jìn)入下一輪循環(huán) continue; } // 執(zhí)行到這里說明字符不是特殊符號 // 檢查下級節(jié)點(diǎn) tempNode = tempNode.getSubNode(c); if(tempNode == null){ // 以begin開頭的字符串不是敏感詞 sb.append(text.charAt(begin)); // 進(jìn)入下一個(gè)位置 position = ++begin; // 重新指向根節(jié)點(diǎn) tempNode = rootNode; } else if(tempNode.isKeywordEnd()){ // 發(fā)現(xiàn)敏感詞,將begin~position字符串替換掉,存 REPLACEMENT (里面是***) sb.append(REPLACEMENT); // 進(jìn)入下一個(gè)位置 begin = ++position; // 重新指向根節(jié)點(diǎn) tempNode = rootNode; } else { // 檢查下一個(gè)字符 position++; } } return sb.toString(); } // 判斷是否為特殊符號,是則返回true,不是則返回false private boolean isSymbol(Character c){ // CharUtils.isAsciiAlphanumeric(c)方法:a、b、1、2···返回true,特殊字符返回false // 0x2E80 ~ 0x9FFF 是東亞的文字范圍,東亞文字范圍我們不認(rèn)為是符號 return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF); } // 前綴樹 private class TrieNode{ // 關(guān)鍵詞結(jié)束標(biāo)識 private boolean isKeywordEnd = false; // 當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)(key是下級字符、value是下級節(jié)點(diǎn)) private Map<Character, TrieNode> subNodes = new HashMap<>(); public boolean isKeywordEnd() { return isKeywordEnd; } public void setKeywordEnd(boolean keywordEnd) { isKeywordEnd = keywordEnd; } // 添加子節(jié)點(diǎn) public void addSubNode(Character c, TrieNode node){ subNodes.put(c, node); } // 獲取子節(jié)點(diǎn) public TrieNode getSubNode(Character c){ return subNodes.get(c); } } }
上面就是過濾敏感詞工具類的全部代碼,接下來我們來解釋一下開發(fā)步驟
開發(fā)過濾敏感詞組件分為三步:
1.定義前綴樹(Tree)
我們將定義前綴樹寫為SensitiveFilter工具類的內(nèi)部類
// 前綴樹 private class TrieNode{ // 關(guān)鍵詞結(jié)束標(biāo)識 private boolean isKeywordEnd = false; // 當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)(key是下級字符、value是下級節(jié)點(diǎn)) private Map<Character, TrieNode> subNodes = new HashMap<>(); public boolean isKeywordEnd() { return isKeywordEnd; } public void setKeywordEnd(boolean keywordEnd) { isKeywordEnd = keywordEnd; } // 添加子節(jié)點(diǎn) public void addSubNode(Character c, TrieNode node){ subNodes.put(c, node); } // 獲取子節(jié)點(diǎn) public TrieNode getSubNode(Character c){ return subNodes.get(c); } }
2.根據(jù)敏感詞,初始化前綴樹
將敏感詞添加到前綴樹中
// 將一個(gè)敏感詞添加到前綴樹中 private void addKeyword(String keyword){ // 首先默認(rèn)指向根 TrieNode tempNode = rootNode; for (int i = 0; i < keyword.length(); i++) { char c = keyword.charAt(i); TrieNode subNode = tempNode.getSubNode(c); if(subNode == null){ // subNode為空,初始化子節(jié)點(diǎn);subNode不為空,直接用就可以了 subNode = new TrieNode(); tempNode.addSubNode(c, subNode); } // 指針指向子節(jié)點(diǎn),進(jìn)入下一輪循環(huán) tempNode = subNode; } // 最后要設(shè)置結(jié)束標(biāo)識 tempNode.setKeywordEnd(true); }
3.編寫過濾敏感詞的方法
如何過濾文本中的敏感詞:
特殊符號怎么處理:
敏感詞前綴樹初始化完畢之后,過濾文本中的敏感詞的算法應(yīng)該如下:
定義三個(gè)指針:
指針1指向Tree樹
指針2指向待過濾字符串段的頭
指針3指向待過濾字符串段的尾
/** * 過濾敏感詞 * @param text 待過濾的文本 * @return 過濾后的文本 */ public String filter(String text){ if(StringUtils.isBlank(text)){ // 待過濾的文本為空,直接返回null return null; } // 指針1,指向樹 TrieNode tempNode = rootNode; // 指針2,指向正在檢測的字符串段的首 int begin = 0; // 指針3,指向正在檢測的字符串段的尾 int position = 0; // 儲存過濾后的文本 StringBuilder sb = new StringBuilder(); while (begin < text.length()){ char c = text.charAt(position); // 跳過符號,比如 “開票”是敏感詞 #開#票# 這個(gè)字符串中間的 '#' 應(yīng)該跳過 if(isSymbol(c)){ // 是特殊字符 // 若指針1處于根節(jié)點(diǎn),將此符號計(jì)入結(jié)果,指針2、3向右走一步 if(tempNode == rootNode){ sb.append(c); begin++; } // 無論符號在開頭或中間,指針3都向下走一步 position++; // 符號處理完,進(jìn)入下一輪循環(huán) continue; } // 執(zhí)行到這里說明字符不是特殊符號 // 檢查下級節(jié)點(diǎn) tempNode = tempNode.getSubNode(c); if(tempNode == null){ // 以begin開頭的字符串不是敏感詞 sb.append(text.charAt(begin)); // 進(jìn)入下一個(gè)位置 position = ++begin; // 重新指向根節(jié)點(diǎn) tempNode = rootNode; } else if(tempNode.isKeywordEnd()){ // 發(fā)現(xiàn)敏感詞,將begin~position字符串替換掉,存 REPLACEMENT (里面是***) sb.append(REPLACEMENT); // 進(jìn)入下一個(gè)位置 begin = ++position; // 重新指向根節(jié)點(diǎn) tempNode = rootNode; } else { // 檢查下一個(gè)字符 position++; } } return sb.toString(); } // 判斷是否為特殊符號,是則返回true,不是則返回false private boolean isSymbol(Character c){ // CharUtils.isAsciiAlphanumeric(c)方法:a、b、1、2···返回true,特殊字符返回false // 0x2E80 ~ 0x9FFF 是東亞的文字范圍,東亞文字范圍我們不認(rèn)為是符號 return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF); }
最后:建議在測試類中測試一下
經(jīng)測試,過濾敏感詞的工具類開發(fā)完成,這個(gè)工具會在接下來的發(fā)布帖子的功能中用到。
“SpringBoot如何實(shí)現(xiàn)過濾敏感詞”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。