日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

利用Trie(字典树)实现敏感词过滤算法

發(fā)布時間:2023/12/20 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 利用Trie(字典树)实现敏感词过滤算法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Trie(字典樹),正如它的名字一樣,其主要的作用就是來存儲字符串的,用它來實現(xiàn)字符串的查找效率比較高,查找的時間復(fù)雜度主要和它的元素(字符串的長度)O(W)相關(guān),但是消耗的內(nèi)存也比較大。
字典樹主要應(yīng)用于:

  • 字符串的檢索
  • 詞頻統(tǒng)計
  • 字符串的排序

利用Trie實現(xiàn)敏感詞過濾器主要有下面三個步驟:

  • 定義前綴樹
  • 根據(jù)敏感詞,初始化前綴樹
  • 編寫過濾敏感詞的算法

定義和初始化前綴樹

  • 根節(jié)點沒有字符
  • 除了根節(jié)點每個節(jié)點都只有一個字符
  • 每個節(jié)點所有的子節(jié)點的字符都不相同

字符串的每個字符作為一個Node節(jié)點,Node’節(jié)點主要有兩部分組成
1.是否為單詞(boolean isKeyWordEnd)
2.節(jié)點所有的子節(jié)點,用map來保存 key是字符,value 是子節(jié)點

//定義前綴樹private class TrieNode {//表示是否為關(guān)鍵詞的結(jié)尾private boolean isKeyWordEnd = false;//子節(jié)點private Map<Character, TrieNode> subNodes = new HashMap<>();//判斷是否是關(guān)鍵詞的結(jié)尾public boolean isKeyWordEnd() {return isKeyWordEnd;}//設(shè)置關(guān)鍵詞的結(jié)尾為truepublic void setKeyWordEnd(boolean isKeyWordEnd) {this.isKeyWordEnd = isKeyWordEnd;}//添加子節(jié)點public void addSubNode(Character c, TrieNode node) {subNodes.put(c, node);}//獲取子節(jié)點public TrieNode getSubNode(Character c) {return subNodes.get(c);}}

根據(jù)敏感詞,初始化前綴樹

//將一個敏感詞添加到前綴樹中private void addKeyWord(String keyword) {TrieNode temp = rootNode;for (int i = 0; i < keyword.length(); i++) {char c = keyword.charAt(i);TrieNode subNode = temp.getSubNode(c);//如果子節(jié)點中不存在該字符節(jié)點if (subNode == null) {subNode = new TrieNode();temp.addSubNode(c, subNode);}//指向下一個節(jié)點,進(jìn)行下一個循環(huán)temp = subNode;//如果遍歷到字符結(jié)束的位置,就要設(shè)置節(jié)點的字符結(jié)束標(biāo)志位為trueif (i == keyword.length() - 1) {temp.setKeyWordEnd(true);}}}

例如把單詞abc插入到前綴樹中,如果用戶輸入ab,盡管abc包含了ab,但是trie中仍然不包含ab這個單詞,所以插入到單詞的最后一個位置時,需要設(shè)置當(dāng)前最后一個節(jié)點的結(jié)束標(biāo)志位為true,代表這是一個完整的敏感詞。

敏感詞過濾算法的實現(xiàn)

設(shè)置三個指針
指針1:初始時指向前綴樹的root根節(jié)點
指針2:初始時指向待過濾字符的頭結(jié)點,表示敏感詞的開頭
指針3:初始時指向待過濾字符的頭結(jié)點,表示敏感詞的末尾
利用StringBuilder接收返回值

在指針1所指向節(jié)點的子節(jié)點中尋找是否出現(xiàn)指針3所指向的字符,如果沒有指針2和指針3進(jìn)入下一個位置,并將滑過的值添加到stringbuilder中。

當(dāng)指針1之指向的節(jié)點的子節(jié)點中能找到指針3指向的值時,指針1指向?qū)?yīng)的子節(jié)點,指針2在原位置不動(疑似敏感詞的開頭位置)

指針3繼續(xù)步進(jìn),此時在指針1對應(yīng)的子節(jié)點中找不動指針3的值f!=c,指針3就要回到指針2的下一個節(jié)點,指針1需要回到根節(jié)點,繼續(xù)尋找以b開頭的字符是不是敏感詞。


指針3繼續(xù)步進(jìn),并與指針1指向的節(jié)點的自己點的值比對,當(dāng)兩者都指向字符’f’的時候,判斷節(jié)點f的敏感詞標(biāo)志位是否為true,如果為true表示找到一個敏感詞,并將其替換為‘***’添加到stringbuilder中,隨后指針2指向指針3的下一個位置即a,指針1重回root,繼續(xù)進(jìn)行過濾。

//敏感詞過濾算法的實現(xiàn)public String filter(String text){if(StringUtils.isBlank(text)){return null;}//指針1TrieNode tempNode=rootNode;//指針2 指向字符的開頭int begin=0;//指針3 指向疑似敏感字符的結(jié)尾int position=0;//結(jié)果StringBuilder sb=new StringBuilder();while(begin<text.length()) {char c = text.charAt(position);//跳過符號if (isSymbol(c)) {//如果指針1處于根節(jié)點,將此符號計入結(jié)果,讓指針2向下走一步if (tempNode==rootNode) {sb.append(c);begin++;}//無論符號在開頭還是中間,指針3都向下走一步position++;continue;}//檢查下級節(jié)點tempNode=tempNode.getSubNode(c);if (tempNode==null){//以begin開頭的字符串不是敏感詞sb.append(text.charAt(begin));//進(jìn)入下一個位置position=++begin;//重新指向根節(jié)點tempNode=rootNode;}else if (tempNode.isKeyWordEnd()){//發(fā)現(xiàn)敏感詞,將begin-position字符串替換點sb.append(REPLACEMENT);//進(jìn)入下一個位置begin=++position;//重新指向根節(jié)點tempNode=rootNode;}else{//檢查下一個字符if (position<text.length()-1){position++;}}}sb.append(text.substring(begin));return sb.toString();}

測試:

@Testpublic void testSensitiveFilter(){String text="這里可以賭博,可以嫖娼,可以吸毒,可以開票";text=sensitiveFilter.filter(text);System.out.println(text);text="這里可以🀁賭博,可以🀂嫖娼,可以🀂🀂🀂吸毒,可以開🀃🀃🀃票";text=sensitiveFilter.filter(text);System.out.println(text);}

結(jié)果:

總結(jié)

以上是生活随笔為你收集整理的利用Trie(字典树)实现敏感词过滤算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。