1. 程式人生 > >DFA敏感詞過濾演算法

DFA敏感詞過濾演算法

運用DFA演算法加密。

首先我先對敏感詞庫初始化,若我的敏感詞庫為

冰毒
白粉
大麻
大壞蛋

初始化之後得到的是下面這樣。:

{冰={毒={isEnd=1}, isEnd=0}, 白={粉={isEnd=1}, isEnd=0}, 大={麻={isEnd=1}, isEnd=0, 壞={蛋={isEnd=1}, isEnd=0}}}。

ok,我把初始化之後的資料用A來表示。假設待檢測的文字為:張三是個大壞蛋,他竟然吸食白粉和冰毒。

後面檢測文字中是否有敏感詞的時候,先把要檢測的文字迭代迴圈,並轉換成charAt值,這樣的話,

如果 A.get(charAt) 為空的話,說明這個字不在敏感詞庫中,比如 "張","三","是","個" ........

如果 A.get(charAt) 不為空的話,說明這個字存在敏感詞庫中,比如 "大","壞","蛋" ...........

假設我們檢測到  "大" "壞" 的時候,發現這個字存在於敏感詞庫中,這個時候需要看專案需求,如果只是檢測 輸入框內是否含有敏感詞,

那這裡就可以不進行判斷了,已經含有敏感詞了。

如果要把所有的敏感詞用 "*" 號替換的話,那就要繼續往下匹配,判斷該敏感詞是否是最後一個......

以上就是基本思路了,下面上程式碼 ,不懂的可以留言給我。。。

溫馨提示:

初始化敏感詞庫的時候

1、加了redis快取

2、敏感詞庫我是放在了伺服器下面

3、編碼格式注意,程式碼裡的編碼格式要與你的敏感詞庫的編碼格式一致。utf-8或者gbk。(win下把txt另存為可以看到,linux下vim txt,:set fileencoding)

linux下檔案編碼格式轉換,這裡是gbk -> utf-8:iconv -f gb18030 -t utf-8 sensitiveword.txt -o sensitiveword.txt

你們用main方法測試的時候,要把快取註釋掉,敏感詞庫路徑改為 你們本地。

/*
 * Project: admin.common
 *
 * File Created at 2017年8月23日
 *
 * Copyright 2016 CMCC Corporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * ZYHY Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license.
 */
package com.cmcc.admin.common.sensitive;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @Type SensitiveWordFilter.java
 * @Desc
 * @author whb
 * @date 2017年8月23日 下午1:56:38
 * @version
 */
public class SensitiveWordFilter {
    @SuppressWarnings("rawtypes")
    private Map sensitiveWordMap = null;
    public static int minMatchType = 1; //最小匹配規則
    public static int maxMatchType = 2; //最大匹配規則

    /**
     * 建構函式,初始化敏感詞庫
     * @throws Exception
     * @since 1.8
     * @author whb
     */
    public SensitiveWordFilter() throws Exception {
        sensitiveWordMap = new SensitiveWordInit().initKeyWord();
    }

    /**
     * 檢查文字中敏感詞的長度
     * @param txt
     * @param beginIndex
     * @param matchType
     * @return 如果存在,則返回敏感詞字元的長度,不存在返回0
     * @since 1.8
     * @author whb
     */
    @SuppressWarnings("rawtypes")
    public int checkSensitiveWord(String txt, int beginIndex, int matchType) {
        Map nowMap = sensitiveWordMap;
        boolean flag = false; //敏感詞結束標識位:用於敏感詞只有1位的情況
        char word = 0;
        int matchFlag = 0; //匹配標識數預設為0
        for (int i = beginIndex; i < txt.length(); i++) {
            word = txt.charAt(i);
            nowMap = (Map) nowMap.get(word); //獲取指定key
            if (nowMap == null) {
                break;//不存在,直接返回
            }
            //輸入的字(排列組合的匹配)出現在敏感詞庫中,判斷是否為最後一個
            matchFlag++; //找到相應key,匹配標識+1
            if (isEnd(nowMap)) { //如果為最後一個匹配規則,結束迴圈,返回匹配標識數
                flag = true; //結束標誌位為true
                if (SensitiveWordFilter.minMatchType == matchType) {
                    break;//最小規則,直接返回,最大規則還需繼續查詢
                }
            }
        }
        if (matchFlag < 2 || !flag) { //長度必須大於等於1,為詞
            matchFlag = 0;
        }
        return matchFlag;
    }

    /**
     * 是否包含敏感詞
     * @param txt
     * @param matchType
     * @return true:是;false:否
     * @since 1.8
     * @author whb
     */
    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) {
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 是否包含敏感詞(重慶專案預設值,按最小匹配規則來,只要有敏感詞就ok)
     * 如果敏感詞庫為:
     *          中
     *          中國
     *          中國人
     *  初始化之後為:{中={isEnd=1, 國={人={isEnd=1}, isEnd=1}}}
     *  測試的文字為:我是一名中國人。
     *  1、按最小規則匹配,  匹配 中 的時候,就為最後一個了 直接break。
     *  2、按最大規則匹配,  匹配 中 的時候,就為最後一個,繼續匹配 國,人。
     * @param txt
     * @return true:是;false:否
     * @since 1.8
     * @author whb
     */
    public boolean isSensitive(String txt) {
        boolean flag = false;
        for (int i = 0; i < txt.length(); i++) {
            int matchFlag = this.checkSensitiveWord(txt, i, 1);
            if (matchFlag > 0) {
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 獲取文字中的敏感詞
     * @param txt
     * @param matchType
     * @return
     * @since 1.8
     * @author whb
     */
    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;
    }

    /**
     * 替換敏感字字元
     * @param txt
     * @param matchType
     * @param replaceChar
     * @return
     * @since 1.8
     * @author whb
     */
    public String replaceSensitiveWord(String txt, int matchType, String replaceChar) {
        String resultTxt = txt;
        Set<String> set = this.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;
    }

    /**
     * 獲取替換字串
     * @param replaceChar
     * @param length
     * @return
     * @since 1.8
     * @author whb
     */
    private String getReplaceChars(String replaceChar, int length) {
        String resultReplace = replaceChar;
        for (int i = 1; i < length; i++) {
            resultReplace += replaceChar;
        }
        return resultReplace;
    }

    /**
     * 判斷是否為最後一個
     * @param nowMap
     * @return
     * @since 1.8
     * @author whb
     */
    @SuppressWarnings("rawtypes")
    private boolean isEnd(Map nowMap) {
        boolean flag = false;
        if ("1".equals(nowMap.get("isEnd"))) {
            flag = true;
        }
        return flag;
    }

    public static void main(String[] args) throws Exception {
        SensitiveWordFilter filter = new SensitiveWordFilter();
        System.out.println("敏感詞的數量:" + filter.sensitiveWordMap.size());
        String string = "王弘博是個大壞蛋,他竟然吸食白粉和冰毒";
        System.out.println("待檢測語句的字數:" + string.length());
        long beginTime = System.currentTimeMillis();
        Set<String> set = filter.getSensitiveWord(string, 1);
         String result = filter.replaceSensitiveWord(string, 1, "*");
        boolean flag = filter.isSensitive(string);
        System.out.println(flag);
        long endTime = System.currentTimeMillis();
          System.out.println("語句中包含敏感詞的個數為:" + set.size() + "。包含:" + set);
         System.out.println("敏感詞處理之後為:"+result);
        System.out.println("總共消耗時間為:" + (endTime - beginTime));
    }
}

/**
 * Revision history
 * -------------------------------------------------------------------------
 *
 * Date Author Note
 * -------------------------------------------------------------------------
 * 2017年8月23日 whb create
 */

/*
 * Project: admin.common
 *
 * File Created at 2017年8月23日
 *
 * Copyright 2016 CMCC Corporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * ZYHY Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license.
 */
package com.cmcc.admin.common.sensitive;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.cmcc.aqb.cache.redis.RedisClient;

/**
 * @Type SensitiveWordInit.java
 * @Desc
 * @author whb
 * @date 2017年8月23日 下午1:57:03
 * @version
 */
public class SensitiveWordInit {

    private static final String ENCODING = "utf-8"; //字元編碼

    @SuppressWarnings("rawtypes")
    public HashMap sensitiveWordMap;

    public SensitiveWordInit() {
        super();
    }

    static RedisClient redisClient = null;
    private static String SPILIT = "#";
    private static int EXPIRE_TIME = 3600;// seconds
    private static String SENSITIVE_WORD = SensitiveWordInit.class.getName();

    private String sensitiveWordKey(String type) {
        StringBuilder sb = new StringBuilder();
        sb.append(type).append(SPILIT).append("sensitiveWordInit");
        return sb.toString();
    }

    /**
     *
     * @return
     * @throws Exception
     * @since 1.8
     * @author whb
     */
    @SuppressWarnings({ "rawtypes", "resource" })
    public Map initKeyWord() {
        try {
            ApplicationContext ac = new ClassPathXmlApplicationContext(new String[] {
                    "spring/datasource.xml", "spring/cache.xml" });
            redisClient = (RedisClient) ac.getBean("redisClient");
            String key = sensitiveWordKey(SENSITIVE_WORD);
            sensitiveWordMap = redisClient.get(key);
            if (sensitiveWordMap == null) {
                Set<String> set = readSensitiveWordFile();
                addSensitiveWordToHashMap(set);
                redisClient.put(key, sensitiveWordMap, EXPIRE_TIME);
            }
            ((AbstractApplicationContext) ac).registerShutdownHook();
            return sensitiveWordMap;
        } catch (Exception e) {
            throw new RuntimeException("初始化敏感詞庫錯誤");
        }
    }

    /**
     * 讀取敏感詞庫,並把內容放到set裡
     * @return
     * @throws Exception
     * @since 1.8
     * @author whb
     */
    private Set<String> readSensitiveWordFile() throws Exception {
        Set<String> set = null;
        File file = new File("/home/sensitiveword.txt");
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
                new FileInputStream(file), ENCODING))) {
            if (file.isFile() && file.exists()) {
                set = new HashSet<String>();
                String txt = null;
                while ((txt = bufferedReader.readLine()) != null) {
                    set.add(txt);
                }
            } else {
                throw new Exception("敏感詞庫檔案不存在");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
        return set;

    }

    /**
     * 讀取敏感詞庫,將敏感詞放入HashSet中,構建一個DFA演算法模型:<br>
     * 中 = {
     *      isEnd = 0
     *      國 = {<br>
     *           isEnd = 1
     *           人 = {isEnd = 0
     *                民 = {isEnd = 1}
     *                }
     *           男  = {
     *                  isEnd = 0
     *                   人 = {
     *                        isEnd = 1
     *                       }
     *               }
     *           }
     *      }
     *  五 = {
     *      isEnd = 0
     *      星 = {
     *          isEnd = 0
     *          紅 = {
     *              isEnd = 0
     *              旗 = {
     *                   isEnd = 1
     *                  }
     *              }
     *          }
     *      }
     * @param keyWordSet
     * @since 1.8
     * @author whb
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    private void addSensitiveWordToHashMap(Set<String> keyWordSet) {
        sensitiveWordMap = new HashMap(keyWordSet.size()); //初始化敏感詞容器,避免擴容操作
        String key = null;
        Map nowMap = null;
        Map<String, String> newWorMap = null;
        Iterator<String> iterator = keyWordSet.iterator();
        while (iterator.hasNext()) {
            key = iterator.next();
            nowMap = sensitiveWordMap;
            for (int i = 0; i < key.length(); i++) {
                char charKey = key.charAt(i); //轉換成char型
                Object wordMap = nowMap.get(charKey);
                if (wordMap != null) {
                    nowMap = (Map) wordMap; //一個一個放進Map中
                } else { //不存在,則構建一個Map,同時將isEnd設定為0,因為它不是最後一個
                    newWorMap = new HashMap<String, String>();
                    newWorMap.put("isEnd", "0");//不是最後一個
                    nowMap.put(charKey, newWorMap);//沒有這個key,就把(isEnd,0) 放在Map中
                    nowMap = newWorMap;
                }
                if (i == key.length() - 1) { //最後一個
                    nowMap.put("isEnd", "1");
                }
            }
        }
    }

}

/**
 * Revision history
 * -------------------------------------------------------------------------
 *
 * Date Author Note
 * -------------------------------------------------------------------------
 * 2017年8月23日 whb create
 */

相關推薦

DFA敏感過濾演算法

運用DFA演算法加密。首先我先對敏感詞庫初始化,若我的敏感詞庫為冰毒白粉大麻大壞蛋初始化之後得到的是下面這樣。:{冰={毒={isEnd=1}, isEnd=0}, 白={粉={isEnd=1}, isEnd=0}, 大={麻={isEnd=1}, isEnd=0, 壞={蛋

敏感過濾演算法:字首樹演算法

背景 平時我們在逛貼吧、牛客網的時候,我們經常可以看到一些形如 “***”的符號,通過上下文,我們也可以很容易猜到這些詞原來是罵人的話,只是被系統和諧了。那麼這是如何實現的呢?作為普通人,我們最先想到的一種辦法就是把所有敏感串存入一個列表中,然後使用者每發一條內容後臺就把該內容與敏感串列表

【python 走進NLP】英文敏感過濾演算法改進版本

中文DFA演算法過濾敏感詞改進版本 # 中文DFA演算法過濾敏感詞改進版本 class Chinese_DFAFilter(): def __init__(self): self.keyword_chains = {} s

C#敏感過濾演算法實現

1.DFA演算法簡介DFA全稱為:Deterministic Finite Automaton,即確定有窮自動機。其特徵為:有一個有限狀態集合和一些從一個狀態通向另一個狀態的邊,每條邊上標記有一個符號,其中一個狀態是初態,某些狀態是終態。但不同於不確定的有限自動機,DFA中不

Java Web敏感過濾演算法

1.DFA演算法DFA演算法的原理可以參考 這裡 ,簡單來說就是通過Map構造出一顆敏感詞樹,樹的每一條由根節點到葉子節點的路徑構成一個敏感詞,例如下圖:程式碼簡單實現如下:public class TextFilterUtil { //日誌 private stat

高效能的敏感過濾演算法 可以忽略大小寫、全半形、簡繁體、特殊符號干擾 (二)

/// <summary> /// 敏感詞過濾 已忽略大小寫 全半形 簡繁體差異 特殊符號 html標籤 干擾 /// </summary> public static class FilterKeyWords { priv

java DFA 敏感過濾

@SuppressWarnings("unchecked") public class SensitiveWordUtils { /** * 只要匹配到一個就返回 */ public static final int

DFA演算法實現Java敏感過濾

      敏感詞、文字過濾是一個網站必不可少的功能,如何設計一個好的、高效的過濾演算法是非常有必要的。前段時間我一個朋友(馬上畢業,接觸程式設計不久)要我幫他看一個文字過濾的東西,它說檢索效率非常慢。我把它程式拿過來一看,整個過程如下:讀取敏感詞庫、如果Ha

DFA演算法實現敏感過濾

DFA,即Deterministic Finite Automaton,也就是確定有窮自動機。比如我們有愛戀、哈哈、感動、靜靜、發呆、太多、啦啦這幾個敏感詞,以上其實是通過HashMap組織成的樹形結構,比如我們通過“太”就可以知道這個字是否是“太多”這個詞的最後一個字,並且

敏感過濾演算法原理之DFA演算法

轉載自:https://blog.csdn.net/chenssy/article/details/26961957敏感詞、文字過濾是一個網站必不可少的功能,如何設計一個好的、高效的過濾演算法是非常有必要的。前段時間我一個朋友(馬上畢業,接觸程式設計不久)要我幫他看一個文字過

Java利用DFA演算法實現敏感過濾

前言: 敏感詞文字過濾是一個網站必不可少的功能,如何設計一個好的、高效的過濾演算法是非常有必要的。作為一般開發人員來說首先考慮的肯定是簡單的匹配,這樣是可以實現功能,但效率比較慢,在高階一點的就是正則表示式,比前一個好一點,但終究還是一丘之貉,非常遺憾,兩種方法都不可取。當

61 dfa 實現敏感過濾

引用 nbsp bsp 概念 pre clas logs code println 基本的概念 Class class=null 【只是在棧內存中有了指向,堆內存並沒有分配內存】 Class class=new Class()【棧內存中有了指向(引用),堆內存也分配了內存

java敏感過濾(庫+演算法)高效率驗證

需求:使用者輸入一段文字,驗證是否包含敏感詞,以及具體的是哪些敏感詞,替換為*等....1.需要一個詞庫,我這裡就是一個從github下載的一個txt檔案。已轉存到百度網盤,點選下載詞庫,提取碼:tk3g2.DFA演算法,效能卓越,請放心使用,直接上java程式碼:packa

PHP實現敏感過濾系統

trie樹 sel 重復 .html ole lang 最大 foreach header PHP實現敏感詞過濾系統 安裝說明 安裝PHP擴展 trie_filter,安裝教程 http://blog.41ms.com/post/39.html 安

Java 敏感過濾,Java 敏感替換,Java 敏感工具類

blog rds log code ima 方法 www enter iteye Java 敏感詞過濾,Java 敏感詞替換,Java 敏感詞工具類 =========================== ?Copyright 蕃薯耀 2017年9月25日 http:

5分鐘Serverless實踐 | 構建無服務器的敏感過濾後端系統

trab 平臺 ase lac mps creat base pen 服務器架構 前言 在上一篇“5分鐘Serverless實踐”系列文章中,我們介紹了什麽是Serverless,以及如何構建一個無服務器的圖片鑒黃Web應用,本文將延續這個話題,以敏感詞過濾為例,介紹如何構

JavaScript 版敏感過濾

    考慮到太多的違禁詞彙,所以縮小化顯示,縮小到讓你看不清楚。如果想看清楚一點,還是去演示地址裡面看吧。消滅敏感詞是每個公民義不容辭的責任!你不站崗我不站崗,誰保衛咱祖國誰來保衛家!讀者們你們要是敢舉報,看我不砍死你! 安裝方法 # 安裝到當前專案 np

敏感過濾工具

SensitivewordEngine.java 敏感詞過濾工具類 package keyFilter; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.uti

php 實現敏感過濾 - PHP擴充套件trie_filter

實現方法1 使用PHP擴充套件trie_filter  安裝:libiconv  wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz tar zxvf libiconv-1.14.tar.gz cd libicon

java HashMap實現中文分器 應用:敏感過濾實現

今天下午部門內部技術分享是分詞器演算法。這次的主講是大名鼎鼎的Ansj分詞器的作者-孫健。 作者簡介: Ansj分詞器作者 elasticsearch-sql(elasticsearch的sql外掛)作者,支援sql查詢 nlp-lang自然語言工具包發起人 NLPCN(自然語言處理