Java过滤敏感词

课程设计做了个博客系统,为了对评论进行敏感词过滤,所以去看了下DFA

在Java中实现敏感词过滤的关键就是DFA算法的实现。首先我们对上图进行剖析。在这过程中我们认为下面这种结构会更加清晰明了。


         同时这里没有状态转换,没有动作,有的只是Query(查找)。我们可以认为,通过S query U、V,通过U query V、P,通过V query U P。通过这样的转变我们可以将状态的转换转变为使用Java集合的查找。

诚然,加入在我们的敏感词库中存在如下几个敏感词:日本人、日本鬼子、毛.泽.东。那么我需要构建成一个什么样的结构呢?

首先:query 日 ---> {本}、query 本 --->{人、鬼子}、query 人 --->{null}、query 鬼 ---> {子}。形如下结构:


         下面我们在对这图进行扩展:


         这样我们就将我们的敏感词库构建成了一个类似与一颗一颗的树,这样我们判断一个词是否为敏感词时就大大减少了检索的匹配范围。比如我们要判断日本人,根据第一个字我们就可以确认需要检索的是那棵树,然后再在这棵树中进行检索。

         但是如何来判断一个敏感词已经结束了呢?利用标识位来判断。

         所以对于这个关键是如何来构建一棵棵这样的敏感词树。下面我已Java中的HashMap为例来实现DFA算法。具体过程如下:

日本人,日本鬼子为例

         1、在hashMap中查询“日”看其是否在hashMap中存在,如果不存在,则证明已“日”开头的敏感词还不存在,则我们直接构建这样的一棵树。跳至3。

         2、如果在hashMap中查找到了,表明存在以“日”开头的敏感词,设置hashMap = hashMap.get("日"),跳至1,依次匹配“本”、“人”。

         3、判断该字是否为该词中的最后一个字。若是表示敏感词结束,设置标志位isEnd = 1,否则设置标志位isEnd = 0;

 

首先需要建立一个敏感词库:

  1. /** 
  2.      * 读取敏感词库,将敏感词放入HashSet中,构建一个DFA算法模型:<br> 
  3.      * 中 = { 
  4.      *      isEnd = 0 
  5.      *      国 = {<br> 
  6.      *           isEnd = 1 
  7.      *           人 = {isEnd = 0 
  8.      *                民 = {isEnd = 1} 
  9.      *                } 
  10.      *           男  = { 
  11.      *                  isEnd = 0 
  12.      *                   人 = { 
  13.      *                        isEnd = 1 
  14.      *                       } 
  15.      *               } 
  16.      *           } 
  17.      *      } 
  18.      *  五 = { 
  19.      *      isEnd = 0 
  20.      *      星 = { 
  21.      *          isEnd = 0 
  22.      *          红 = { 
  23.      *              isEnd = 0 
  24.      *              旗 = { 
  25.      *                   isEnd = 1 
  26.      *                  } 
  27.      *              } 
  28.      *          } 
  29.      *      } 
  30.      */ 
 
/**
 * 创建敏感词汇树
 * @param keyWordSet
 */
public void createWords(Set<String> keyWordSet) {
    sensitiveWordMap = new HashMap(keyWordSet.size());
    Map nowMap = null;
    Map<String,String> wordMap = null;

    String key = null;

    for (String word : keyWordSet) {
        nowMap = sensitiveWordMap;
        key = word;
        for (int index=0 ; index<key.length() ; index++) {

            char keyChar = key.charAt(index);
            Object newWordMap = nowMap.get(keyChar);

            if (newWordMap!=null) {
                nowMap = (Map) newWordMap;

            } else {
                wordMap = new HashMap<>();
                wordMap.put("isEnd","0");
                nowMap.put(keyChar,wordMap);
                nowMap = wordMap;
            }

            if (index == key.length()-1) {
                nowMap.put("isEnd","1");
            }
        }
    }
}

敏感词库我们一个简单的方法给实现了,那么如何实现检索呢?检索过程无非就是hashMap的get实现,找到就证明该词为敏感词,否则不为敏感词。过程如下:假如我们匹配“中国人民万岁”。

         1、第一个字“中”,我们在hashMap中可以找到。得到一个新的map = hashMap.get("")。

         2、如果map == null,则不是敏感词。否则跳至3

         3、获取map中的isEnd,通过isEnd是否等于1来判断该词是否为最后一个。如果isEnd == 1表示该词为敏感词,否则跳至1。

         通过这个步骤我们可以判断“中国人民”为敏感词,但是如果我们输入“中国女人”则不是敏感词了

/**
 * 获取敏感词汇集
 * @param txt
 * @param matchType
 * @return
 */
public Set<String> getSensitiveWord(String txt,int matchType) {
    Set<String> sensitiveWordList = new HashSet<>();

    for (int index=0;index<txt.length();index++) {
        int length = checkSensitiveWord(txt,index,matchType);
        if (length>0) {
            sensitiveWordList.add(txt.substring(index,index+length));
            index = index + length - 1;
        }
    }

    return sensitiveWordList;
}

/**
 * 匹配 判断敏感词汇
 * @param txt
 * @param beginIndex
 * @param matchType
 * @return
 */
public int checkSensitiveWord(String txt,int beginIndex,int matchType) {
    boolean flag = false;
    int wordFlag = 0;
    char word = 0;
    Map nowMap = sensitiveWordMap;

    for (int index=beginIndex ; index<txt.length() ; index++) {
        word = txt.charAt(index);
        nowMap = (Map) nowMap.get(word);
        if (nowMap!=null) {
            wordFlag++;
            if ("1".equals(nowMap.get("isEnd"))) {
                flag = true;
                if (FilterUtil.minMatchTYpe == matchType) {
                    break;//最小匹配直接跳出
                }
            }
        }  else {     //不存在,直接返回
            break;
        }
    }

    System.out.println(wordFlag+" "+flag);
    if (wordFlag<2 || !flag) {
        return 0;
    }

    return wordFlag;
}
需要一个词库: 点击下载词库 ,提取码: tk3g


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值