溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java怎么使用DFA算法實現(xiàn)敏感詞過濾

發(fā)布時間:2023-03-25 11:58:46 來源:億速云 閱讀:113 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“Java怎么使用DFA算法實現(xiàn)敏感詞過濾”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Java怎么使用DFA算法實現(xiàn)敏感詞過濾”吧!

1 前言

敏感詞過濾就是你在項目中輸入某些字(比如輸入xxoo相關(guān)的文字時)時要能檢測出來,很多項目中都會有一個敏感詞管理模塊,在敏感詞管理模塊中你可以加入敏感詞,然后根據(jù)加入的敏感詞去過濾輸入內(nèi)容中的敏感詞并進(jìn)行相應(yīng)的處理,要么提示,要么高亮顯示,要么直接替換成其它的文字或者符號代替。

敏感詞過濾的做法有很多,其中有比較常用的如下幾種:

1.查詢數(shù)據(jù)庫當(dāng)中的敏感詞,循環(huán)每一個敏感詞,然后去輸入的文本中從頭到尾搜索一遍,看是否存在此敏感詞,有則做相應(yīng)的處理,這種方式講白了就是找到一個處理一個。

優(yōu)點(diǎn):so easy。用java代碼實現(xiàn)基本沒什么難度。

缺點(diǎn):這效率是非常低的,如果是英文時你會發(fā)現(xiàn)一個很無語的事情,比如英文a是敏感詞,那我如果是一篇英文文檔,那程序它得處理多少次敏感詞?誰能告訴我?

2.傳說中的DFA算法(有限狀態(tài)機(jī)),也正是我要給大家分享的,畢竟感覺比較通用,算法的原理希望大家能夠自己去網(wǎng)上查查

資料,這里就不詳細(xì)說明了。

優(yōu)點(diǎn):至少比上面那sb效率高點(diǎn)。

缺點(diǎn):對于學(xué)過算法的應(yīng)該不難,對于沒學(xué)過算法的用起來也不難,就是理解起來有點(diǎn)gg疼,匹配效率也不高,比較耗費(fèi)內(nèi)存,

敏感詞越多,內(nèi)存占用的就越大。

2 代碼實現(xiàn)

2.1 敏感詞庫初始化

在項目啟動前讀取數(shù)據(jù),將敏感詞加載到Map中,具體實現(xiàn)如下:

建表語句:

CREATE TABLE `sensitive_word` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `content` varchar(50) NOT NULL COMMENT '關(guān)鍵詞',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
 
INSERT INTO `fuying`.`sensitive_word` (`id`, `content`, `create_time`, `update_time`) VALUES (1, '吳名氏', '2023-03-02 14:21:36', '2023-03-02 14:21:36');

實體類SensitiveWord.java:

package com.wkf.workrecord.tools.dfa.entity;
 
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
 
import java.io.Serializable;
import java.util.Date;
 
/**
 * @author wuKeFan
 * @date 2023-03-02 13:48:58
 */
@Data
@TableName("sensitive_word")
public class SensitiveWord implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
 
    private String content;
 
    private Date createTime;
 
    private Date updateTime;
 
}

數(shù)據(jù)庫持久類SensitiveWordMapper.java:

package com.wkf.workrecord.tools.dfa.mapper;
 
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wkf.workrecord.tools.dfa.entity.SensitiveWord;
 
/**
 * @author wuKeFan
 * @date 2023-03-02 13:50:16
 */
public interface SensitiveWordMapper extends BaseMapper<SensitiveWord> {
}

service類SensitiveWordService.java和SensitiveWordServiceImpl.java:

package com.wkf.workrecord.tools.dfa.service;
 
import com.baomidou.mybatisplus.extension.service.IService;
import com.wkf.workrecord.tools.dfa.entity.SensitiveWord;
 
import java.util.Set;
 
/**
 * 敏感詞過濾服務(wù)類
 * @author wuKeFan
 * @date 2023-03-02 13:47:04
 */
public interface SensitiveWordService extends IService<SensitiveWord> {
 
    Set<String> sensitiveWordFiltering(String text);
 
}
package com.wkf.workrecord.tools.dfa.service;
 
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wkf.workrecord.tools.dfa.mapper.SensitiveWordMapper;
import com.wkf.workrecord.tools.dfa.SensitiveWordUtils;
import com.wkf.workrecord.tools.dfa.entity.SensitiveWord;
import org.springframework.stereotype.Service;
import java.util.Set;
 
/**
 * @author wuKeFan
 * @date 2023-03-02 13:48:04
 */
@Service
public class SensitiveWordServiceImpl extends ServiceImpl<SensitiveWordMapper, SensitiveWord> implements SensitiveWordService{
 
    @Override
    public Set<String> sensitiveWordFiltering(String text) {
        // 得到敏感詞有哪些,傳入2表示獲取所有敏感詞
        return SensitiveWordUtils.getSensitiveWord(text, 2);
    }
}

敏感詞過濾工具類SensitiveWordUtils:

package com.wkf.workrecord.tools.dfa;
 
import com.wkf.workrecord.tools.dfa.entity.SensitiveWord;
import lombok.extern.slf4j.Slf4j;
 
import java.util.*;
 
/**
 * 敏感詞過濾工具類
 * @author wuKeFan
 * @date 2023-03-02 13:45:19
 */
@Slf4j
@SuppressWarnings("unused")
public class SensitiveWordUtils {
 
    /**
     * 敏感詞庫
     */
    public static final Map<Object, Object> sensitiveWordMap = new HashMap<>();
 
    /**
     * 只過濾最小敏感詞
     */
    public static int minMatchTYpe = 1;
 
    /**
     * 過濾所有敏感詞
     */
    public static int maxMatchType = 2;
 
    /**
     * 初始化敏感詞
     */
    public static void initKeyWord(List<SensitiveWord> sensitiveWords) {
        try {
            // 從敏感詞集合對象中取出敏感詞并封裝到Set集合中
            Set<String> keyWordSet = new HashSet<>();
            for (SensitiveWord s : sensitiveWords) {
                keyWordSet.add(s.getContent().trim());
            }
            // 將敏感詞庫加入到HashMap中
            addSensitiveWordToHashMap(keyWordSet);
        }
        catch (Exception e) {
            log.error("初始化敏感詞出錯,", e);
        }
    }
 
    /**
     * 封裝敏感詞庫
     *
     * @param keyWordSet 敏感詞庫列表
     */
    private static void addSensitiveWordToHashMap(Set<String> keyWordSet) {
        // 敏感詞
        String key;
        // 用來按照相應(yīng)的格式保存敏感詞庫數(shù)據(jù)
        Map<Object, Object> nowMap;
        // 用來輔助構(gòu)建敏感詞庫
        Map<Object, Object> newWorMap;
        // 使用一個迭代器來循環(huán)敏感詞集合
        for (String s : keyWordSet) {
            key = s;
            // 等于敏感詞庫,HashMap對象在內(nèi)存中占用的是同一個地址,所以此nowMap對象的變化,sensitiveWordMap對象也會跟著改變
            nowMap = sensitiveWordMap;
            for (int i = 0; i < key.length(); i++) {
                // 截取敏感詞當(dāng)中的字,在敏感詞庫中字為HashMap對象的Key鍵值
                char keyChar = key.charAt(i);
 
                // 判斷這個字是否存在于敏感詞庫中
                Object wordMap = nowMap.get(keyChar);
                if (wordMap != null) {
                    nowMap = (Map<Object, Object>) wordMap;
                } else {
                    newWorMap = new HashMap<>();
                    newWorMap.put("isEnd", "0");
                    nowMap.put(keyChar, newWorMap);
                    nowMap = newWorMap;
                }
 
                // 如果該字是當(dāng)前敏感詞的最后一個字,則標(biāo)識為結(jié)尾字
                if (i == key.length() - 1) {
                    nowMap.put("isEnd", "1");
                }
                log.info("封裝敏感詞庫過程:" + sensitiveWordMap);
            }
            log.info("查看敏感詞庫數(shù)據(jù):" + sensitiveWordMap);
        }
    }
 
    /**
     * 敏感詞庫敏感詞數(shù)量
     *
     * @return 返回數(shù)量
     */
    public static int getWordSize() {
        return SensitiveWordUtils.sensitiveWordMap.size();
    }
 
    /**
     * 是否包含敏感詞
     *
     * @param txt 敏感詞
     * @param matchType 匹配類型
     * @return 返回結(jié)果
     */
    public static boolean isContainSensitiveWord(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<>();
 
        for (int i = 0; i < txt.length(); i++) {
            int length = checkSensitiveWord(txt, i, matchType);
            if (length > 0) {
                // 將檢測出的敏感詞保存到集合中
                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;
        String replaceString;
        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 返回結(jié)果
     */
    private static String getReplaceChars(String replaceChar, int length) {
        StringBuilder resultReplace = new StringBuilder(replaceChar);
        for (int i = 1; i < length; i++) {
            resultReplace.append(replaceChar);
        }
        return resultReplace.toString();
    }
 
    /**
     * 檢查敏感詞數(shù)量
     *
     * @param txt 敏感詞
     * @param beginIndex 開始下標(biāo)
     * @param matchType 匹配類型
     * @return 返回數(shù)量
     */
    public static int checkSensitiveWord(String txt, int beginIndex, int matchType) {
        boolean flag = false;
        // 記錄敏感詞數(shù)量
        int matchFlag = 0;
        char word;
        Map<Object, Object> nowMap = SensitiveWordUtils.sensitiveWordMap;
        for (int i = beginIndex; i < txt.length(); i++) {
            word = txt.charAt(i);
            // 判斷該字是否存在于敏感詞庫中
            nowMap = (Map<Object, Object>) nowMap.get(word);
            if (nowMap != null) {
                matchFlag++;
                // 判斷是否是敏感詞的結(jié)尾字,如果是結(jié)尾字則判斷是否繼續(xù)檢測
                if ("1".equals(nowMap.get("isEnd"))) {
                    flag = true;
                    // 判斷過濾類型,如果是小過濾則跳出循環(huán),否則繼續(xù)循環(huán)
                    if (SensitiveWordUtils.minMatchTYpe == matchType) {
                        break;
                    }
                }
            }
            else {
                break;
            }
        }
        if (!flag) {
            matchFlag = 0;
        }
        return matchFlag;
    }
 
}

項目啟動完成后執(zhí)行初始化敏感關(guān)鍵字StartInit.java:

package com.wkf.workrecord.tools.dfa;
 
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wkf.workrecord.tools.dfa.entity.SensitiveWord;
import com.wkf.workrecord.tools.dfa.mapper.SensitiveWordMapper;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
 
/**
 * 初始化敏感關(guān)鍵字
 * @author wuKeFan
 * @date 2023-03-02 13:57:45
 */
@Component
public class StartInit {
 
    @Resource
    private SensitiveWordMapper sensitiveWordMapper;
 
    @PostConstruct
    public void init() {
        // 從數(shù)據(jù)庫中獲取敏感詞對象集合(調(diào)用的方法來自Dao層,此方法是service層的實現(xiàn)類)
        List<SensitiveWord> sensitiveWords = sensitiveWordMapper.selectList(new QueryWrapper<>());
        // 構(gòu)建敏感詞庫
        SensitiveWordUtils.initKeyWord(sensitiveWords);
    }
 
}

2.2 編寫測試類

編寫測試腳本測試效果.代碼如下:

    @Test
    public void sensitiveWordTest() {
        Set<String> set = sensitiveWordService.sensitiveWordFiltering("吳名氏到此一游");
        for (String string : set) {
            System.out.println(string);
        }
    }

執(zhí)行結(jié)果如下:

Java怎么使用DFA算法實現(xiàn)敏感詞過濾

到此,相信大家對“Java怎么使用DFA算法實現(xiàn)敏感詞過濾”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI