1、什麼是敏感詞過濾,有什麼用處?
敏感詞、文字過濾是一個網站必不可少的功能,如何設計一個好的、高效的過濾算法是非常有必要的。基本上每個網站中都有對需要處理的不好字眼進行處理,那我們今天就來使用DFA算法實現敏感詞過濾這個功能。
2、什麼是DFA?
在實現文字過濾的算法中,DFA是唯一比較好的實現算法。DFA即Deterministic Finite Automaton,也就是確定有窮自動機,它是是通過event和當前的state得到下一個state,即event+state=nextstate。在Java中實現敏感詞過濾的關鍵就是DFA算法的實現;就相當於一個查找的過程。
3、程序實現:
//初始化敏感詞庫
//將敏感詞加入到HashMap中,構建DFA算法模型
public class SensitiveTxtInit {
//字節編碼
private String ENCODING = "GBK";
@SuppressWarnings("rawtypes")
public HashMap sensitiveTxtMap;
public SensitiveTxtInit(){
super();
}
@SuppressWarnings("rawtypes")
public Map initKeyTxt(){
try {
//讀取敏感詞庫
Set<String> keyTxtSet = readSensitiveWordFile();
//將敏感詞庫加入到HashMap中
addSensitiveWordToHashMap(keyTxtSet);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return sensitiveTxtMap;
}
@SuppressWarnings("resource")
private Set<String> readSensitiveWordFile() throws Exception{
Set<String> set = null;
File file = new File("D:\\SensitiveTxt.txt");//讀取文件
InputStreamReader read = new InputStreamReader(new FileInputStream(file),ENCODING);
try {
if(file.isFile() && file.exists())//文件流是否存在
{
set = new HashSet<String>();
BufferedReader bufferedReader = new BufferedReader(read);
String txt = null;
while((txt = bufferedReader.readLine()) != null){//讀取文件,將文件內容放入到set中
set.add(txt);
}
}
else{
throw new Exception("敏感詞庫文件不存在");
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally {
read.close();//關閉文件流
}
return set;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void addSensitiveWordToHashMap(Set<String> keyWordSet){
sensitiveTxtMap = new HashMap(keyWordSet.size());//初始化敏感詞容器,減少擴容操作
String key = null;
Map nowMap = null;
Map<String, String> newWorMap = null;
//迭代keyWordSet
Iterator<String> iterator = keyWordSet.iterator();
while(iterator.hasNext()){
key = iterator.next();//關鍵字
nowMap = sensitiveTxtMap;
for(int i = 0 ; i < key.length() ; i++){
char keyChar = key.charAt(i);//轉換成char型
Object wordMap = nowMap.get(keyChar);//獲取
if(wordMap != null){ //如果存在該key,直接賦值
nowMap = (Map) wordMap;
}else{//不存在則,則構建一個map,同時將isEnd設置爲0,因爲他不是最後一個
newWorMap = new HashMap<String,String>();
newWorMap.put("isEnd", "0"); //不是最後一個
nowMap.put(keyChar, newWorMap);
nowMap = newWorMap;
}
if(i == key.length() - 1){
nowMap.put("isEnd", "1"); //最後一個
}
}
}
}
}
//敏感詞過濾,實現及測試
public class SensitiveTxtFilter {
@SuppressWarnings({ "rawtypes" })
private Map sensitiveWordMap = null;
public static int minMatchTYpe = 1;//最小匹配規則
public static int maxMatchType = 2;//最大匹配規則
/*
* 構造函數,初始化敏感詞庫
*/
public SensitiveTxtFilter(){
sensitiveWordMap = new SensitiveTxtInit().initKeyTxt();
}
/**
* 判斷文字是否包含敏感字符
* @author helongjun
* @date 2014年4月20日 下午4:28:30
* @param txt 文字
* @param matchType 匹配規則 1:最小匹配規則,2:最大匹配規則
* @return 若包含返回true,否則返回false
* @version 1.0
*/
public boolean isContaintSensitiveWord(String txt,int matchType){
boolean flag = false;
for(int i = 0 ; i < txt.length() ; i++){
int matchFlag = this.CheckSensitiveWord(txt, i, matchType); //判斷是否包含敏感字符
if(matchFlag > 0){ //大於0存在,返回true
flag = true;
}
}
return flag;
}
/**
* 獲取文字中的敏感詞
* @author helongjun
* @date 2014年4月20日 下午5:10:52
* @param txt 文字
* @param matchType 匹配規則 1:最小匹配規則,2:最大匹配規則
* @return
* @version 1.0
*/
public 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){ //存在,加入list中
sensitiveWordList.add(txt.substring(i, i+length));
i = i + length - 1; //減1的原因,是因爲for會自增
}
}
return sensitiveWordList;
}
/**
* 替換敏感字字符
* @author helongjun
* @date 2014年4月20日 下午5:12:07
* @param txt
* @param matchType
* @param replaceChar 替換字符,默認*
* @version 1.0
*/
public 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;
}
/**
* 獲取替換字符串
* @author helongjun
* @date 2014年4月20日 下午5:21:19
* @param replaceChar
* @param length
* @return
* @version 1.0
*/
private String getReplaceChars(String replaceChar,int length){
String resultReplace = replaceChar;
for(int i = 1 ; i < length ; i++){
resultReplace += replaceChar;
}
return resultReplace;
}
/**
* 檢查文字中是否包含敏感字符,檢查規則如下:<br>
* @author helongjun
* @date 2014年4月20日 下午4:31:03
* @param txt
* @param beginIndex
* @param matchType
* @return,如果存在,則返回敏感詞字符的長度,不存在返回0
* @version 1.0
*/
@SuppressWarnings("rawtypes")
public int CheckSensitiveWord(String txt,int beginIndex,int matchType){
boolean flag = false; //敏感詞結束標識位:用於敏感詞只有1位的情況
int matchFlag = 0; //匹配標識數默認爲0
char word = 0;
Map nowMap = sensitiveWordMap;
for(int i = beginIndex; i < txt.length() ; i++){
word = txt.charAt(i);
nowMap = (Map) nowMap.get(word); //獲取指定key
if(nowMap != null){ //存在,則判斷是否爲最後一個
matchFlag++; //找到相應key,匹配標識+1
if("1".equals(nowMap.get("isEnd"))){ //如果爲最後一個匹配規則,結束循環,返回匹配標識數
flag = true; //結束標誌位爲true
if(SensitiveTxtFilter.minMatchTYpe == matchType){ //最小規則,直接返回,最大規則還需繼續查找
break;
}
}
}
else{ //不存在,直接返回
break;
}
}
if(matchFlag < 2 || !flag){ //長度必須大於等於1,爲詞
matchFlag = 0;
}
return matchFlag;
}
public static void main(String[] args) {
SensitiveTxtFilter filter = new SensitiveTxtFilter();
System.out.println("敏感詞庫總數:"+filter.sensitiveWordMap.size());
String string = "太多的傷感情懷操你妹侷限於飼養基地 熒幕中的情節,主人公嘗你媽的用某種方式漸漸的很瀟灑地釋自殺指南懷那些自己經歷的傷感。"
+ "然後法輪功 我們的扮演的角色就是跟隨着主人公的喜紅客聯盟 怒哀樂而過於牽強的把自己的情感也附加於銀幕情節中,然後感動就流淚,"
+ "難過就躺在某一個人的懷裏盡情的闡述心扉或者手機卡複製器一個人一杯紅酒一部電影在夜三級片 深人靜的晚上,關上電話靜靜的發呆着。";
System.out.println("待檢測語句字數:" + string.length());
long beginTime = System.currentTimeMillis();
Set<String> set = filter.getSensitiveWord(string, 1);
long endTime = System.currentTimeMillis();
System.out.println("語句中包含敏感詞的個數爲:" + set.size() + "。包含:" + set);
System.out.println("總共消耗時間爲:" + (endTime - beginTime));
String replaceStr = filter.replaceSensitiveWord(string, 2, "legend");
System.out.println("替換後的字符串是:"+replaceStr);
}
}
注意: 需要新建一個詞庫文件SensitiveTxt.txt,文件內容格式如下: