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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

那么,传说中的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;
}

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

可爱博主:AlanLee

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

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

java实现敏感词过滤(DFA算法)的更多相关文章

  1. Java实现敏感词过滤 - DFA算法

    Java实现DFA算法进行敏感词过滤 封装工具类如下: 使用前需对敏感词库进行初始化: SensitiveWordUtil.init(sensitiveWordSet); package cn.swf ...

  2. Java实现敏感词过滤 - IKAnalyzer中文分词工具

    IKAnalyzer 是一个开源的,基于java语言开发的轻量级的中文分词工具包. 官网: https://code.google.com/archive/p/ik-analyzer/ 本用例借助 I ...

  3. 敏感词过滤的算法原理之DFA算法

    参考文档 http://blog.csdn.net/chenssy/article/details/26961957 敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有 ...

  4. Java实现敏感词过滤

    敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来 ...

  5. Java实现敏感词过滤(转)

    敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来 ...

  6. 转:Java实现敏感词过滤

    敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来 ...

  7. Java实现敏感词过滤代码

    原文:http://www.open-open.com/code/view/1445762764148 import java.io.BufferedReader; import java.io.Fi ...

  8. 敏感词汇过滤DFA算法

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Tex ...

  9. java类敏感词过滤类

    package com.fpx.pcs.prealert.process.service.impl; import java.util.HashMap;import java.util.HashSet ...

随机推荐

  1. AutoMapper(二)

    返回总目录 首先,先创建一个控制台项目,引用AutoMapper程序集,创建三个类User,UserDto,UserMappingProfile,下面的知识点的演示都以此项目为基础,代码分别如下: n ...

  2. SQL SERVER全面优化-------Expert for SQL Server 诊断系列

    现在很多用户被数据库的慢的问题所困扰,又苦于花钱请一个专业的DBA成本太高.软件维护人员对数据库的了解又不是那么深入,所以导致问题迟迟不能解决,或只能暂时解决不能得到根治.开发人员解决数据问题基本又是 ...

  3. Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!

    随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...

  4. ABP框架 - 缓存

    文档目录 本节内容: 简介 ICacheManager ICache ITypedCache 配置 实体缓存 EntityCache 是如何工作 Redis 缓存集成 简介 ABP提供了一个缓存接口, ...

  5. Atitit. 破解  拦截 绕过 网站 手机 短信 验证码  方式 v2 attilax 总结

    Atitit. 破解  拦截 绕过 网站 手机 短信 验证码  方式 v2 attilax 总结 1. 验证码的前世今生11.1. 第一代验证码 图片验证码11.2. 第二代验证码  用户操作 ,比如 ...

  6. 【转】c#、wpf 字符串,color,brush之间的转换

    转自:http://www.cnblogs.com/wj-love/archive/2012/09/14/2685281.html 1,将#3C3C3C 赋给background this.selec ...

  7. .NET MVC Razor模板预编译(二)

    在前面一片文章:<.NET MVC4 Razor视图预编译(一)> 里面我采用的是PrecompiledMvcViewEngineContrib组件进行预编译视图的虚拟地址注册,但是这个组 ...

  8. Cesium原理篇:GroundPrimitive

    今天来看看GroundPrimitive,选择GroundPrimitive有三个目的:1 了解GroundPrimitive和Primitive的区别和关系 2 createGeometry的特殊处 ...

  9. 打造高效前端工作环境 - tmux

    打造高效前端工作环境 - tmux 前言  现在前端开发可不容易啊,先打开个VIM,然后再打开个lite-server,一不小心写个ES2015还要打开个gulp来做预编译,如果能把这么多个窗口放在一 ...

  10. 利用WCF双工模式实现即时通讯

    概述 WCF陆陆续续也用过多次,但每次都是浅尝辄止,以将够解决问题为王道,这几天稍闲,特寻了些资料看,昨晚尝试使用WCF的双工模式实现了一个简单的即时通讯程序,通过服务端转发实现客户端之间的通讯.这只 ...