java利用DFA算法实现敏感词过滤功能
前言
敏感词过滤应该是不用给大家过多的解释吧?讲白了就是你在项目中输入某些字(比如输入xxoo相关的文字时)时要能检
测出来,很多项目中都会有一个敏感词管理模块,在敏感词管理模块中你可以加入敏感词,然后根据加入的敏感词去过滤输
入内容中的敏感词并进行相应的处理,要么提示,要么高亮显示,要么直接替换成其它的文字或者符号代替。
敏感词过滤的做法有很多,我简单描述我现在理解的几种:
①查询数据库当中的敏感词,循环每一个敏感词,然后去输入的文本中从头到尾搜索一遍,看是否存在此敏感词,有则做相
应的处理,这种方式讲白了就是找到一个处理一个。
优点:so easy。用java代码实现基本没什么难度。
缺点:这效率让我心中奔过十万匹*,而且匹配的是不是有些蛋疼,如果是英文时你会发现一个很无语的事情,比如英文
a是敏感词,那我如果是一篇英文文档,那程序它妹的得处理多少次敏感词?谁能告诉我?
②传说中的dfa算法(有穷自动机),也正是我要给大家分享的,毕竟感觉比较通用,算法的原理希望大家能够自己去网上查查
资料,这里就不详细说明了。
优点:至少比上面那sb效率高点。
缺点:对于学过算法的应该不难,对于没学过算法的用起来也不难,就是理解起来有点gg疼,匹配效率也不高,比较耗费内存,
敏感词越多,内存占用的就越大。
③第三种在这里要特别说明一下,那就是你自己去写一个算法吧,或者在现有的算法的基础上去优化,这也是追求的至高境界之一。
那么,传说中的dfa算法是怎么实现的呢?
第一步:敏感词库初始化(将敏感词用dfa算法的原理封装到敏感词库中,敏感词库采用hashmap保存),代码如下:
package com.cfwx.rox.web.sysmgr.util; import java.util.hashmap; import java.util.hashset; import java.util.iterator; import java.util.list; import java.util.map; import java.util.set; import com.cfwx.rox.web.common.model.entity.sensitiveword; /** * 敏感词库初始化 * * @author alanlee * */ public class sensitivewordinit { /** * 敏感词库 */ public hashmap sensitivewordmap; /** * 初始化敏感词 * * @return */ public map initkeyword(list<sensitiveword> sensitivewords) { try { // 从敏感词集合对象中取出敏感词并封装到set集合中 set<string> keywordset = new hashset<string>(); for (sensitiveword s : sensitivewords) { keywordset.add(s.getcontent().trim()); } // 将敏感词库加入到hashmap中 addsensitivewordtohashmap(keywordset); } catch (exception e) { e.printstacktrace(); } return sensitivewordmap; } /** * 封装敏感词库 * * @param keywordset */ @suppresswarnings("rawtypes") private void addsensitivewordtohashmap(set<string> keywordset) { // 初始化hashmap对象并控制容器的大小 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(); // 等于敏感词库,hashmap对象在内存中占用的是同一个地址,所以此nowmap对象的变化,sensitivewordmap对象也会跟着改变 nowmap = sensitivewordmap; for (int i = 0; i < key.length(); i++) { // 截取敏感词当中的字,在敏感词库中字为hashmap对象的key键值 char keychar = key.charat(i); // 判断这个字是否存在于敏感词库中 object wordmap = nowmap.get(keychar); if (wordmap != null) { nowmap = (map) wordmap; } else { newwormap = new hashmap<string, string>(); newwormap.put("isend", "0"); nowmap.put(keychar, newwormap); nowmap = newwormap; } // 如果该字是当前敏感词的最后一个字,则标识为结尾字 if (i == key.length() - 1) { nowmap.put("isend", "1"); } system.out.println("封装敏感词库过程:"+sensitivewordmap); } system.out.println("查看敏感词库数据:" + sensitivewordmap); } } }
第二步:写一个敏感词过滤工具类,里面可以写上自己需要的方法,代码如下:
package com.cfwx.rox.web.sysmgr.util; import java.util.hashset; import java.util.iterator; import java.util.map; import java.util.set; /** * 敏感词过滤工具类 * * @author alanlee * */ public class sensitivewordengine { /** * 敏感词库 */ public static map sensitivewordmap = null; /** * 只过滤最小敏感词 */ public static int minmatchtype = 1; /** * 过滤所有敏感词 */ public static int maxmatchtype = 2; /** * 敏感词库敏感词数量 * * @return */ public static int getwordsize() { if (sensitivewordengine.sensitivewordmap == null) { return 0; } return sensitivewordengine.sensitivewordmap.size(); } /** * 是否包含敏感词 * * @param txt * @param matchtype * @return */ public static boolean iscontaintsensitiveword(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; } /** * 获取敏感词内容 * * @param txt * @param matchtype * @return 敏感词内容 */ public static 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) { // 将检测出的敏感词保存到集合中 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 = 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 */ private static string getreplacechars(string replacechar, int length) { string resultreplace = replacechar; for (int i = 1; i < length; i++) { resultreplace += replacechar; } return resultreplace; } /** * 检查敏感词数量 * * @param txt * @param beginindex * @param matchtype * @return */ public static int checksensitiveword(string txt, int beginindex, int matchtype) { boolean flag = false; // 记录敏感词数量 int matchflag = 0; char word = 0; map nowmap = sensitivewordengine.sensitivewordmap; for (int i = beginindex; i < txt.length(); i++) { word = txt.charat(i); // 判断该字是否存在于敏感词库中 nowmap = (map) nowmap.get(word); if (nowmap != null) { matchflag++; // 判断是否是敏感词的结尾字,如果是结尾字则判断是否继续检测 if ("1".equals(nowmap.get("isend"))) { flag = true; // 判断过滤类型,如果是小过滤则跳出循环,否则继续循环 if (sensitivewordengine.minmatchtype == matchtype) { break; } } } else { break; } } if (!flag) { matchflag = 0; } return matchflag; } }
第三步:一切都准备就绪,当然是查询好数据库当中的敏感词,并且开始过滤咯,代码如下:
@suppresswarnings("rawtypes") @override public set<string> sensitivewordfiltering(string text) { // 初始化敏感词库对象 sensitivewordinit sensitivewordinit = new sensitivewordinit(); // 从数据库中获取敏感词对象集合(调用的方法来自dao层,此方法是service层的实现类) list<sensitiveword> sensitivewords = sensitiveworddao.getsensitivewordlistall(); // 构建敏感词库 map sensitivewordmap = sensitivewordinit.initkeyword(sensitivewords); // 传入sensitivewordengine类中的敏感词库 sensitivewordengine.sensitivewordmap = sensitivewordmap; // 得到敏感词有哪些,传入2表示获取所有敏感词 set<string> set = sensitivewordengine.getsensitiveword(text, 2); return set; }
最后一步:在controller层写一个方法给前端请求,前端获取到需要的数据并进行相应的处理,代码如下:
/** * 敏感词过滤 * * @param text * @return */ @requestmapping(value = "/word/filter") @responsebody public respvo sensitivewordfiltering(string text) { respvo respvo = new respvo(); try { set<string> set = sensitivewordservice.sensitivewordfiltering(text); respvo.setresult(set); } catch (exception e) { throw new roxexception("过滤敏感词出错,请联系维护人员"); } return respvo; }
总结
以上就是这篇文章的全部内容了,代码中写了不少的注释,大家可以动动自己的脑筋好好的理解一下。希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。