平時咱們在逛貼吧的時候,咱們常常能夠看到一些形如 「***」的符號,經過上下文,咱們也能夠很容易猜到這些詞原來是罵人的話,只是被系統和諧了。那麼這是如何實現的呢?做爲普通人,咱們最早想到的一種辦法就是把全部敏感串存入一個列表中,而後用戶每發一條內容後臺就把該內容與敏感串列表的每一項進行匹配,而後把匹配的字符進行和諧。顯然這樣的效率是很低的。很是影響性能,那麼咱們有沒有其餘的算法呢?這就是我這篇博文打算介紹的。html
原理講解node
1.首先創建個敏感詞前綴樹算法
根節點爲空app
2.準備好待處理字符串: 哈哈大王八子大豬蹄子哦 ,聲明三個指針,分別指向前綴樹的根節點以及待處理字符串的開始字符post
3.position指向的字符與根節點的全部子節點進行匹配,不匹配,position 和 begin分別指向待處理字符串的下一個字符,tempNode依舊指向 根節點性能
4.依舊不匹配,position 和begin繼續向前走一位,指向「大」,treeNode依舊指向根節點ui
5.此時 根節點有一個子節點 與 position指向的字符相等,都爲‘大’,則tempNode 指向該節點,同時position前進一步,指向‘王’3d
6.此時把position指向的‘王’ 和 tempNode的全部子節點進行匹配,匹配失敗,說明 從begin起頭全部串是不存在敏感詞的,能夠直接輸出。此時begin前進一位,position回退到begin的位置,tempNode回退到根節點指針
7.此時再把position指向的‘王’與tempNode的全部子節點進行匹配,匹配成功,因此tempNode指向該節點,同時position前進一位,指向'八'htm
8.此時再把position指向的‘王’ 與tempNode的全部子節點進行匹配,匹配成功,此時tempNode 指向它的子節點‘八’,同時position前進一位。
9.繼續把position指向的字符與tempNode的全部子節點進行匹配,匹配失敗。說明以begin起頭的不存在非法字符,能夠加入到結果集中。 此時begin向前走一位,position回退到begin的位置,同時tempNode回退到根節點。
10.同理,能夠發現子'子'不匹配,則直接把它加入結果集,同時position 和begin 向前走一位,tempNode指向根節點。
此時position指向 ‘大’,與tempNode的全部 子節點進行匹配,匹配成功,則position和tempNode都走一位,循環執行....
直到position指向‘子’,tempNode指向‘蹄’
11.此時把position與tempNode的全部子節點進行匹配,匹配成功,tempNode指向它的子節點‘子’,此時檢查發現tempNode是敏感詞樹的葉子節點,說明從begin+1開始的位置 到 position這段是敏感詞,用和諧詞替換掉。替換以後position前進一位,begin跳到position的位置,tempNode回退到根節點
以上,就是所有流程啦,理解了以後看代碼就簡單多啦
代碼講解
1.前綴樹節點結構
private class TreeNode{
//是否最後一個字
private boolean isKeyWordsEnd = false;
//子節點
private Map<Character,TreeNode> subNodes = new HashMap<>();
public void addSubNode(Character key, TreeNode node){
subNodes.put(key,node);
}
public TreeNode getSubNode(Character key){
return subNodes.get(key);
}
public boolean isKeyWordsEnd(){
return isKeyWordsEnd;
}
public void setKeyWordsEnd(Boolean end){
isKeyWordsEnd = end;
}
2.構建前綴樹的方法
public void addSensitiveWord(String words){
TreeNode tempNode = rootNode;
for(int i = 0; i < words.length(); i++){
Character c = words.charAt(i);
if(!isSymbol(c)){
continue;
}
TreeNode node = tempNode.getSubNode(c);
if (node == null){
node = new TreeNode();
tempNode.addSubNode(c,node);
}
// 指針移動
tempNode = node;
//若是到了最後一個字符
if(i == words.length() -1){
tempNode.setKeyWordsEnd(true);
}
}
}
3.算法具體實現
public String filter(String text){
if (StringUtils.isEmpty(text)){
return text;
}
String sensitiveWords = "***";
StringBuilder result = new StringBuilder();
TreeNode tempNode = rootNode;
int begin = 0;
int position = 0;
while (position < text.length()){
Character c = text.charAt(position);
//若是非東亞字符,則直接跳過 ??
if(!isSymbol(c)){ //每次
if(tempNode == rootNode){
result.append(c);
begin++;
}
position++;
continue;
}
tempNode = tempNode.getSubNode(c);
//若是匹配失敗
if(tempNode == null){
//說明以begin起頭的那一段不存在非法詞彙
result.append(text.charAt(begin));
begin++;
position = begin;
tempNode = rootNode;
continue;
}else if(tempNode.isKeyWordsEnd()){
//替換敏感詞
result.append(sensitiveWords);
position++;
begin = position;
tempNode = rootNode;
}else {
position++;
}
}
result.append(text.substring(begin)); //把剩下的動加入合法集
return result.toString();
}
小結
最近一直在作項目,因此有一段時間沒寫文章了,項目也快完成了,就把在項目中使用的一個算法作了下總結,但願能給讀者一些幫助。