利用 DFA 算法實現文字過濾


一、DFA 算法簡介

在實現文字過濾的算法中,DFA是唯一比較好的實現算法。

DFA 全稱為:Deterministic Finite Automaton,即確定有窮自動機。其特征為:有一個有限狀態集合和一些從一個狀態通向另一個狀態的邊,每條邊上標記有一個符號,其中一個狀態是初態,某些狀態是終態。但不同於不確定的有限自動機,DFA 中不會有從同一狀態出發的兩條邊標志有相同的符號。

簡單點說就是,它是是通過 event 和當前的 state 得到下一個 state,即 event + state= nextstate。理解為系統中有多個節點,通過傳遞進入的 event,來確定走哪個路由至另一個節點,而節點是有限的。

二、DEA 算法實踐敏感詞過濾

1. 敏感詞庫構造

以王八蛋和王八羔子兩個敏感詞來進行描述,首先構建敏感詞庫,該詞庫名稱為SensitiveMap,這兩個詞的二叉樹構造為:

用 hash 表構造為:

{
    "王":{
        "isEnd":"0",
        "八":{
            "羔":{
                "子":{
                    "isEnd":"1"
                },
                "isEnd":"0"
            },
            "isEnd":"0",
            "蛋":{
                "isEnd":"1"
            }
        }
    }
}

怎么用代碼實現這種數據結構呢?

    /**
     * 讀取敏感詞庫,將敏感詞放入HashSet中,構建一個DFA算法模型
     *
     * @param keyWordSet 敏感詞庫
     */
    public Map<String, Object> addSensitiveWordToHashMap(Set<String> keyWordSet) {
        //初始化敏感詞容器,減少擴容操作
        Map<String, Object> map = new HashMap(Math.max((int) (keyWordSet.size() / .75f) + 1, 16));
        //迭代keyWordSet
        for (String aKeyWordSet : keyWordSet) {
            Map nowMap = map;
            for (int i = 0; i < aKeyWordSet.length(); i++) {
                //轉換成char型
                char keyChar = aKeyWordSet.charAt(i);
                //獲取
                Object wordMap = nowMap.get(keyChar);
                //如果存在該key,直接賦值
                if (wordMap != null) {
                    nowMap = (Map) wordMap;
                } else {     //不存在則,則構建一個map,同時將isEnd設置為0
                    Map<String, String> newWorMap = new HashMap<>(3);
                    newWorMap.put("isEnd", "0");
                    nowMap.put(keyChar, newWorMap);
                    nowMap = newWorMap;
                }
                //判斷最后一個
                if (i == aKeyWordSet.length() - 1) {
                    nowMap.put("isEnd", "1");
                }
            }
        }
        return map;
    }

2. 敏感詞過濾

以上面例子構造出來的 SensitiveMap 為敏感詞庫進行示意,假設這里輸入的關鍵字為:王八不好,流程圖如下:

怎么用代碼實現這個流程圖邏輯呢?

    /**
     * 查找字符串中是否包含敏感字符
     *
     * @param txt 輸入的字符串
     * @return 如果存在,則返回敏感字符串;不存在,則返回空字符串
     */
    public static String findSensitiveWord(String txt) {
        SensitiveWordInit sensitiveWordInit = SpringContextHolder.getBean(SensitiveWordInit.class);
        Map<String, Object> sensitiveWordMap = sensitiveWordInit.getSensitiveWordMap();
        StringBuilder sensitiveWord = new StringBuilder();
        // 敏感詞結束標志位,表示匹配到了最后一位
        boolean flag = false;
        for (int i = 0; i < txt.length(); i++) {
            char word = txt.charAt(i);
            // 獲取指定 key
            sensitiveWordMap = (Map) sensitiveWordMap.get(word);
            // 不存在,直接返回沒有敏感詞
            if (sensitiveWordMap == null) {
                break;
            }
            //存在,存儲該敏感詞,並判斷是否為最后一個
            sensitiveWord.append(word);
            //如果為最后一個匹配規則,結束循環
            if ("1".equals(sensitiveWordMap.get("isEnd"))) {
                flag = true;
                break;
            }
        }
        // 表示匹配到了完整敏感詞
        if (flag == true) {
            return sensitiveWord.toString();
        }
        return "";
    }

三、優化思路

對於“王*八&&蛋”這樣的詞,中間填充了無意義的字符來混淆,在我們做敏感詞搜索時,同樣應該做一個無意義詞的過濾,當循環到這類無意義的字符時進行跳過,避免干擾。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM