zoukankan      html  css  js  c++  java
  • java实现敏感词过滤(DFA算法)

    小Alan在最近的开发中遇到了敏感词过滤,便去网上查阅了很多敏感词过滤的资料,在这里也和大家分享一下自己的理解。

    敏感词过滤应该是不用给大家过多的解释吧?讲白了就是你在项目中输入某些字(比如输入xxoo相关的文字时)时要能检

    测出来,很多项目中都会有一个敏感词管理模块,在敏感词管理模块中你可以加入敏感词,然后根据加入的敏感词去过滤输

    入内容中的敏感词并进行相应的处理,要么提示,要么高亮显示,要么直接替换成其它的文字或者符号代替。 

    敏感词过滤的做法有很多,我简单描述我现在理解的几种:

    ①查询数据库当中的敏感词,循环每一个敏感词,然后去输入的文本中从头到尾搜索一遍,看是否存在此敏感词,有则做相

    应的处理,这种方式讲白了就是找到一个处理一个。

    优点:so easy。用java代码实现基本没什么难度。

    缺点:这效率让我心中奔过十万匹草泥马,而且匹配的是不是有些蛋疼,如果是英文时你会发现一个很无语的事情,比如英文

    a是敏感词,那我如果是一篇英文文档,那程序它妹的得处理多少次敏感词?谁能告诉我?

    ②传说中的DFA算法(有穷自动机),也正是我要给大家分享的,毕竟感觉比较通用,算法的原理希望大家能够自己去网上查查

    资料,这里就不详细说明了。

    优点:至少比上面那sb效率高点。

    缺点:对于学过算法的应该不难,对于没学过算法的用起来也不难,就是理解起来有点gg疼,匹配效率也不高,比较耗费内存,

    敏感词越多,内存占用的就越大。

    ③第三种在这里要特别说明一下,那就是你自己去写一个算法吧,或者在现有的算法的基础上去优化,这也是小Alan追求的至

    高境界之一,如果哪位淫兄有自己的想法一定别忘了小Alan,可以加小Alan的QQ:810104041教小Alan两招耍耍。

    那么,传说中的DFA算法是怎么实现的呢?

    第一步:敏感词库初始化(将敏感词用DFA算法的原理封装到敏感词库中,敏感词库采用HashMap保存),代码如下:

      1 package com.cfwx.rox.web.sysmgr.util;
      2 
      3 import java.util.HashMap;
      4 import java.util.HashSet;
      5 import java.util.Iterator;
      6 import java.util.List;
      7 import java.util.Map;
      8 import java.util.Set;
      9 
     10 import com.cfwx.rox.web.common.model.entity.SensitiveWord;
     11 
     12 /**
     13  * 敏感词库初始化
     14  * 
     15  * @author AlanLee
     16  *
     17  */
     18 public class SensitiveWordInit
     19 {
     20     /**
     21      * 敏感词库
     22      */
     23     public HashMap sensitiveWordMap;
     24 
     25     /**
     26      * 初始化敏感词
     27      * 
     28      * @return
     29      */
     30     public Map initKeyWord(List<SensitiveWord> sensitiveWords)
     31     {
     32         try
     33         {
     34             // 从敏感词集合对象中取出敏感词并封装到Set集合中
     35             Set<String> keyWordSet = new HashSet<String>();
     36             for (SensitiveWord s : sensitiveWords)
     37             {
     38                 keyWordSet.add(s.getContent().trim());
     39             }
     40             // 将敏感词库加入到HashMap中
     41             addSensitiveWordToHashMap(keyWordSet);
     42         }
     43         catch (Exception e)
     44         {
     45             e.printStackTrace();
     46         }
     47         return sensitiveWordMap;
     48     }
     49 
     50     /**
     51      * 封装敏感词库
     52      * 
     53      * @param keyWordSet
     54      */
     55     @SuppressWarnings("rawtypes")
     56     private void addSensitiveWordToHashMap(Set<String> keyWordSet)
     57     {
     58         // 初始化HashMap对象并控制容器的大小
     59         sensitiveWordMap = new HashMap(keyWordSet.size());
     60         // 敏感词
     61         String key = null;
     62         // 用来按照相应的格式保存敏感词库数据
     63         Map nowMap = null;
     64         // 用来辅助构建敏感词库
     65         Map<String, String> newWorMap = null;
     66         // 使用一个迭代器来循环敏感词集合
     67         Iterator<String> iterator = keyWordSet.iterator();
     68         while (iterator.hasNext())
     69         {
     70             key = iterator.next();
     71             // 等于敏感词库,HashMap对象在内存中占用的是同一个地址,所以此nowMap对象的变化,sensitiveWordMap对象也会跟着改变
     72             nowMap = sensitiveWordMap;
     73             for (int i = 0; i < key.length(); i++)
     74             {
     75                 // 截取敏感词当中的字,在敏感词库中字为HashMap对象的Key键值
     76                 char keyChar = key.charAt(i);
     77 
     78                 // 判断这个字是否存在于敏感词库中
     79                 Object wordMap = nowMap.get(keyChar);
     80                 if (wordMap != null)
     81                 {
     82                     nowMap = (Map) wordMap;
     83                 }
     84                 else
     85                 {
     86                     newWorMap = new HashMap<String, String>();
     87                     newWorMap.put("isEnd", "0");
     88                     nowMap.put(keyChar, newWorMap);
     89                     nowMap = newWorMap;
     90                 }
     91 
     92                 // 如果该字是当前敏感词的最后一个字,则标识为结尾字
     93                 if (i == key.length() - 1)
     94                 {
     95                     nowMap.put("isEnd", "1");
     96                 }
     97                 System.out.println("封装敏感词库过程:"+sensitiveWordMap);
     98             }
     99             System.out.println("查看敏感词库数据:" + sensitiveWordMap);
    100         }
    101     }
    102 }

    第二步:写一个敏感词过滤工具类,里面可以写上自己需要的方法,代码如下:

      1 package com.cfwx.rox.web.sysmgr.util;
      2 
      3 import java.util.HashSet;
      4 import java.util.Iterator;
      5 import java.util.Map;
      6 import java.util.Set;
      7 
      8 /**
      9  * 敏感词过滤工具类
     10  * 
     11  * @author AlanLee
     12  *
     13  */
     14 public class SensitivewordEngine
     15 {
     16     /**
     17      * 敏感词库
     18      */
     19     public static Map sensitiveWordMap = null;
     20 
     21     /**
     22      * 只过滤最小敏感词
     23      */
     24     public static int minMatchTYpe = 1;
     25 
     26     /**
     27      * 过滤所有敏感词
     28      */
     29     public static int maxMatchType = 2;
     30 
     31     /**
     32      * 敏感词库敏感词数量
     33      * 
     34      * @return
     35      */
     36     public static int getWordSize()
     37     {
     38         if (SensitivewordEngine.sensitiveWordMap == null)
     39         {
     40             return 0;
     41         }
     42         return SensitivewordEngine.sensitiveWordMap.size();
     43     }
     44 
     45     /**
     46      * 是否包含敏感词
     47      * 
     48      * @param txt
     49      * @param matchType
     50      * @return
     51      */
     52     public static boolean isContaintSensitiveWord(String txt, int matchType)
     53     {
     54         boolean flag = false;
     55         for (int i = 0; i < txt.length(); i++)
     56         {
     57             int matchFlag = checkSensitiveWord(txt, i, matchType);
     58             if (matchFlag > 0)
     59             {
     60                 flag = true;
     61             }
     62         }
     63         return flag;
     64     }
     65 
     66     /**
     67      * 获取敏感词内容
     68      * 
     69      * @param txt
     70      * @param matchType
     71      * @return 敏感词内容
     72      */
     73     public static Set<String> getSensitiveWord(String txt, int matchType)
     74     {
     75         Set<String> sensitiveWordList = new HashSet<String>();
     76 
     77         for (int i = 0; i < txt.length(); i++)
     78         {
     79             int length = checkSensitiveWord(txt, i, matchType);
     80             if (length > 0)
     81             {
     82                 // 将检测出的敏感词保存到集合中
     83                 sensitiveWordList.add(txt.substring(i, i + length));
     84                 i = i + length - 1;
     85             }
     86         }
     87 
     88         return sensitiveWordList;
     89     }
     90 
     91     /**
     92      * 替换敏感词
     93      * 
     94      * @param txt
     95      * @param matchType
     96      * @param replaceChar
     97      * @return
     98      */
     99     public static String replaceSensitiveWord(String txt, int matchType, String replaceChar)
    100     {
    101         String resultTxt = txt;
    102         Set<String> set = getSensitiveWord(txt, matchType);
    103         Iterator<String> iterator = set.iterator();
    104         String word = null;
    105         String replaceString = null;
    106         while (iterator.hasNext())
    107         {
    108             word = iterator.next();
    109             replaceString = getReplaceChars(replaceChar, word.length());
    110             resultTxt = resultTxt.replaceAll(word, replaceString);
    111         }
    112 
    113         return resultTxt;
    114     }
    115 
    116     /**
    117      * 替换敏感词内容
    118      * 
    119      * @param replaceChar
    120      * @param length
    121      * @return
    122      */
    123     private static String getReplaceChars(String replaceChar, int length)
    124     {
    125         String resultReplace = replaceChar;
    126         for (int i = 1; i < length; i++)
    127         {
    128             resultReplace += replaceChar;
    129         }
    130 
    131         return resultReplace;
    132     }
    133 
    134     /**
    135      * 检查敏感词数量
    136      * 
    137      * @param txt
    138      * @param beginIndex
    139      * @param matchType
    140      * @return
    141      */
    142     public static int checkSensitiveWord(String txt, int beginIndex, int matchType)
    143     {
    144         boolean flag = false;
    145         // 记录敏感词数量
    146         int matchFlag = 0;
    147         char word = 0;
    148         Map nowMap = SensitivewordEngine.sensitiveWordMap;
    149         for (int i = beginIndex; i < txt.length(); i++)
    150         {
    151             word = txt.charAt(i);
    152             // 判断该字是否存在于敏感词库中
    153             nowMap = (Map) nowMap.get(word);
    154             if (nowMap != null)
    155             {
    156                 matchFlag++;
    157                 // 判断是否是敏感词的结尾字,如果是结尾字则判断是否继续检测
    158                 if ("1".equals(nowMap.get("isEnd")))
    159                 {
    160                     flag = true;
    161                     // 判断过滤类型,如果是小过滤则跳出循环,否则继续循环
    162                     if (SensitivewordEngine.minMatchTYpe == matchType)
    163                     {
    164                         break;
    165                     }
    166                 }
    167             }
    168             else
    169             {
    170                 break;
    171             }
    172         }
    173         if (!flag)
    174         {
    175             matchFlag = 0;
    176         }
    177         return matchFlag;
    178     }
    179 
    180 }

    第三步:一切都准备就绪,当然是查询好数据库当中的敏感词,并且开始过滤咯,代码如下:

     1  @SuppressWarnings("rawtypes")
     2     @Override
     3     public Set<String> sensitiveWordFiltering(String text)
     4     {
     5         // 初始化敏感词库对象
     6         SensitiveWordInit sensitiveWordInit = new SensitiveWordInit();
     7         // 从数据库中获取敏感词对象集合(调用的方法来自Dao层,此方法是service层的实现类)
     8         List<SensitiveWord> sensitiveWords = sensitiveWordDao.getSensitiveWordListAll();
     9         // 构建敏感词库
    10         Map sensitiveWordMap = sensitiveWordInit.initKeyWord(sensitiveWords);
    11         // 传入SensitivewordEngine类中的敏感词库
    12         SensitivewordEngine.sensitiveWordMap = sensitiveWordMap;
    13         // 得到敏感词有哪些,传入2表示获取所有敏感词
    14         Set<String> set = SensitivewordEngine.getSensitiveWord(text, 2);
    15         return set;
    16     }

    最后一步:在Controller层写一个方法给前端请求,前端获取到需要的数据并进行相应的处理,代码如下:

     1  /**
     2      * 敏感词过滤
     3      * 
     4      * @param text
     5      * @return
     6      */
     7     @RequestMapping(value = "/word/filter")
     8     @ResponseBody
     9     public RespVo sensitiveWordFiltering(String text)
    10     {
    11         RespVo respVo = new RespVo();
    12         try
    13         {
    14             Set<String> set = sensitiveWordService.sensitiveWordFiltering(text);
    15             respVo.setResult(set);
    16         }
    17         catch (Exception e)
    18         {
    19             throw new RoxException("过滤敏感词出错,请联系维护人员");
    20         }
    21 
    22         return respVo;
    23     }

    小Alan在代码中写了不少的注释,希望大家能够动动自己的脑筋好好的理解一下。

    可爱博主:AlanLee

    博客地址:http://www.cnblogs.com/AlanLee

    本文出自博客园,欢迎大家加入博客园。

  • 相关阅读:
    第五周学习进度条
    课堂实验4.1(环数组)
    每日站立会议(3)
    每日站立会议(2)
    找水王
    购买一批书的最低价格
    每日站立会议(1)
    NABCD分析
    团队开发博客
    返回一个二维整数数组中的最大子数组之和(环)
  • 原文地址:https://www.cnblogs.com/AlanLee/p/5329555.html
Copyright © 2011-2022 走看看