java利用DFA算法實(shí)現(xiàn)敏感詞過(guò)濾功能
前言
敏感詞過(guò)濾應(yīng)該是不用給大家過(guò)多的解釋吧?講白了就是你在項(xiàng)目中輸入某些字(比如輸入xxoo相關(guān)的文字時(shí))時(shí)要能檢
測(cè)出來(lái),很多項(xiàng)目中都會(huì)有一個(gè)敏感詞管理模塊,在敏感詞管理模塊中你可以加入敏感詞,然后根據(jù)加入的敏感詞去過(guò)濾輸
入內(nèi)容中的敏感詞并進(jìn)行相應(yīng)的處理,要么提示,要么高亮顯示,要么直接替換成其它的文字或者符號(hào)代替。
敏感詞過(guò)濾的做法有很多,我簡(jiǎn)單描述我現(xiàn)在理解的幾種:
①查詢數(shù)據(jù)庫(kù)當(dāng)中的敏感詞,循環(huán)每一個(gè)敏感詞,然后去輸入的文本中從頭到尾搜索一遍,看是否存在此敏感詞,有則做相
應(yīng)的處理,這種方式講白了就是找到一個(gè)處理一個(gè)。
優(yōu)點(diǎn):so easy。用java代碼實(shí)現(xiàn)基本沒(méi)什么難度。
缺點(diǎn):這效率低,而且匹配的是不是有些無(wú)語(yǔ),如果是英文時(shí)你會(huì)發(fā)現(xiàn)一個(gè)很無(wú)語(yǔ)的事情,比如英文
a是敏感詞,那我如果是一篇英文文檔,那程序它妹的得處理多少次敏感詞?誰(shuí)能告訴我?
②傳說(shuō)中的DFA算法(有窮自動(dòng)機(jī)),也正是我要給大家分享的,畢竟感覺(jué)比較通用,算法的原理希望大家能夠自己去網(wǎng)上查查
資料,這里就不詳細(xì)說(shuō)明了。
優(yōu)點(diǎn):至少比上面那sb效率高點(diǎn)。
缺點(diǎn):對(duì)于學(xué)過(guò)算法的應(yīng)該不難,對(duì)于沒(méi)學(xué)過(guò)算法的用起來(lái)也不難,就是理解起來(lái)有點(diǎn)gg疼,匹配效率也不高,比較耗費(fèi)內(nèi)存,
敏感詞越多,內(nèi)存占用的就越大。
③第三種在這里要特別說(shuō)明一下,那就是你自己去寫(xiě)一個(gè)算法吧,或者在現(xiàn)有的算法的基礎(chǔ)上去優(yōu)化,這也是追求的至高境界之一。
那么,傳說(shuō)中的DFA算法是怎么實(shí)現(xiàn)的呢?
第一步:敏感詞庫(kù)初始化(將敏感詞用DFA算法的原理封裝到敏感詞庫(kù)中,敏感詞庫(kù)采用HashMap保存),代碼如下:
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;
/**
* 敏感詞庫(kù)初始化
*
* @author AlanLee
*
*/
public class SensitiveWordInit
{
/**
* 敏感詞庫(kù)
*/
public HashMap sensitiveWordMap;
/**
* 初始化敏感詞
*
* @return
*/
public Map initKeyWord(List<SensitiveWord> sensitiveWords)
{
try
{
// 從敏感詞集合對(duì)象中取出敏感詞并封裝到Set集合中
Set<String> keyWordSet = new HashSet<String>();
for (SensitiveWord s : sensitiveWords)
{
keyWordSet.add(s.getContent().trim());
}
// 將敏感詞庫(kù)加入到HashMap中
addSensitiveWordToHashMap(keyWordSet);
}
catch (Exception e)
{
e.printStackTrace();
}
return sensitiveWordMap;
}
/**
* 封裝敏感詞庫(kù)
*
* @param keyWordSet
*/
@SuppressWarnings("rawtypes")
private void addSensitiveWordToHashMap(Set<String> keyWordSet)
{
// 初始化HashMap對(duì)象并控制容器的大小
sensitiveWordMap = new HashMap(keyWordSet.size());
// 敏感詞
String key = null;
// 用來(lái)按照相應(yīng)的格式保存敏感詞庫(kù)數(shù)據(jù)
Map nowMap = null;
// 用來(lái)輔助構(gòu)建敏感詞庫(kù)
Map<String, String> newWorMap = null;
// 使用一個(gè)迭代器來(lái)循環(huán)敏感詞集合
Iterator<String> iterator = keyWordSet.iterator();
while (iterator.hasNext())
{
key = iterator.next();
// 等于敏感詞庫(kù),HashMap對(duì)象在內(nèi)存中占用的是同一個(gè)地址,所以此nowMap對(duì)象的變化,sensitiveWordMap對(duì)象也會(huì)跟著改變
nowMap = sensitiveWordMap;
for (int i = 0; i < key.length(); i++)
{
// 截取敏感詞當(dāng)中的字,在敏感詞庫(kù)中字為HashMap對(duì)象的Key鍵值
char keyChar = key.charAt(i);
// 判斷這個(gè)字是否存在于敏感詞庫(kù)中
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)前敏感詞的最后一個(gè)字,則標(biāo)識(shí)為結(jié)尾字
if (i == key.length() - 1)
{
nowMap.put("isEnd", "1");
}
System.out.println("封裝敏感詞庫(kù)過(guò)程:"+sensitiveWordMap);
}
System.out.println("查看敏感詞庫(kù)數(shù)據(jù):" + sensitiveWordMap);
}
}
}第二步:寫(xiě)一個(gè)敏感詞過(guò)濾工具類(lèi),里面可以寫(xiě)上自己需要的方法,代碼如下:
package com.cfwx.rox.web.sysmgr.util;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* 敏感詞過(guò)濾工具類(lèi)
*
* @author AlanLee
*
*/
public class SensitivewordEngine
{
/**
* 敏感詞庫(kù)
*/
public static Map sensitiveWordMap = null;
/**
* 只過(guò)濾最小敏感詞
*/
public static int minMatchTYpe = 1;
/**
* 過(guò)濾所有敏感詞
*/
public static int maxMatchType = 2;
/**
* 敏感詞庫(kù)敏感詞數(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)
{
// 將檢測(cè)出的敏感詞保存到集合中
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);
// 判斷該字是否存在于敏感詞庫(kù)中
nowMap = (Map) nowMap.get(word);
if (nowMap != null)
{
matchFlag++;
// 判斷是否是敏感詞的結(jié)尾字,如果是結(jié)尾字則判斷是否繼續(xù)檢測(cè)
if ("1".equals(nowMap.get("isEnd")))
{
flag = true;
// 判斷過(guò)濾類(lèi)型,如果是小過(guò)濾則跳出循環(huán),否則繼續(xù)循環(huán)
if (SensitivewordEngine.minMatchTYpe == matchType)
{
break;
}
}
}
else
{
break;
}
}
if (!flag)
{
matchFlag = 0;
}
return matchFlag;
}
}第三步:一切都準(zhǔn)備就緒,當(dāng)然是查詢好數(shù)據(jù)庫(kù)當(dāng)中的敏感詞,并且開(kāi)始過(guò)濾咯,代碼如下:
@SuppressWarnings("rawtypes")
@Override
public Set<String> sensitiveWordFiltering(String text)
{
// 初始化敏感詞庫(kù)對(duì)象
SensitiveWordInit sensitiveWordInit = new SensitiveWordInit();
// 從數(shù)據(jù)庫(kù)中獲取敏感詞對(duì)象集合(調(diào)用的方法來(lái)自Dao層,此方法是service層的實(shí)現(xiàn)類(lèi))
List<SensitiveWord> sensitiveWords = sensitiveWordDao.getSensitiveWordListAll();
// 構(gòu)建敏感詞庫(kù)
Map sensitiveWordMap = sensitiveWordInit.initKeyWord(sensitiveWords);
// 傳入SensitivewordEngine類(lèi)中的敏感詞庫(kù)
SensitivewordEngine.sensitiveWordMap = sensitiveWordMap;
// 得到敏感詞有哪些,傳入2表示獲取所有敏感詞
Set<String> set = SensitivewordEngine.getSensitiveWord(text, 2);
return set;
}最后一步:在Controller層寫(xiě)一個(gè)方法給前端請(qǐng)求,前端獲取到需要的數(shù)據(jù)并進(jìn)行相應(yīng)的處理,代碼如下:
/**
* 敏感詞過(guò)濾
*
* @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("過(guò)濾敏感詞出錯(cuò),請(qǐng)聯(lián)系維護(hù)人員");
}
return respVo;
}總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,代碼中寫(xiě)了不少的注釋?zhuān)蠹铱梢詣?dòng)動(dòng)自己的腦筋好好的理解一下。希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- JavaEE Filter敏感詞過(guò)濾的方法實(shí)例詳解
- JavaWeb中的filter過(guò)濾敏感詞匯案例詳解
- Java實(shí)現(xiàn)DFA算法對(duì)敏感詞、廣告詞過(guò)濾功能示例
- Java實(shí)戰(zhàn)之敏感詞過(guò)濾器
- JAVA使用前綴樹(shù)(Tire樹(shù))實(shí)現(xiàn)敏感詞過(guò)濾、詞典搜索
- Java使用DFA算法實(shí)現(xiàn)敏感詞過(guò)濾的示例代碼
- Java 過(guò)濾器實(shí)現(xiàn)敏感詞匯過(guò)濾功能
- Java數(shù)據(jù)敏感詞轉(zhuǎn)換成符號(hào)的方法詳解
- Java 敏感詞檢測(cè)工具的實(shí)現(xiàn)
相關(guān)文章
SpringBoot整合token實(shí)現(xiàn)登錄認(rèn)證的示例代碼
本文主要介紹了SpringBoot整合token實(shí)現(xiàn)登錄認(rèn)證的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
SpringBoot集成JWT令牌詳細(xì)說(shuō)明
這篇文章主要介紹了SpringBoot集成JWT令牌詳細(xì)說(shuō)明,JWT方式校驗(yàn)方式更加簡(jiǎn)單便捷化,無(wú)需通過(guò)redis緩存,而是直接根據(jù)token取出保存的用戶信息,以及對(duì)token可用性校驗(yàn),單點(diǎn)登錄,驗(yàn)證token更為簡(jiǎn)單,需要的朋友可以參考下2023-10-10
詳解java封裝實(shí)現(xiàn)Excel建表讀寫(xiě)操作
這篇文章給大家分享了java封裝實(shí)現(xiàn)Excel建表讀寫(xiě)操作的相關(guān)知識(shí)點(diǎn)內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。2018-08-08
IDEA設(shè)置maven修改settings.xml配置文件無(wú)法加載倉(cāng)庫(kù)的解決方案
這篇文章主要介紹了IDEA設(shè)置maven修改settings.xml配置文件無(wú)法加載倉(cāng)庫(kù)的解決方案,幫助大家更好的利用IDEA進(jìn)行JAVA的開(kāi)發(fā)學(xué)習(xí),感興趣的朋友可以了解下2021-01-01
淺談Java(SpringBoot)基于zookeeper的分布式鎖實(shí)現(xiàn)
這篇文章主要介紹了Java(SpringBoot)基于zookeeper的分布式鎖實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03

