使用DFA算法对敏感词进行过滤
项目目录结构如下:

其中resources资源目录中:
stopwd.txt :停顿词,匹配时间直接过滤。
wd.txt:敏感词库。
1、WordFilter敏感词过滤类:
package com.skyer.sensitivewdfilter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 思路: 创建一个FilterSet,枚举了0~65535的所有char是否是某个敏感词开头的状态
*
* 判断是否是 敏感词开头 | | 是 不是 获取头节点 OK--下一个字 然后逐级遍历,DFA算法
*/
public class WordFilter {
private static final FilterSet set = new FilterSet(); // 存储首字
private static final Map<Integer, WordNode> nodes = new HashMap<Integer, WordNode>(1024, 1); // 存储节点
private static final Set<Integer> stopwdSet = new HashSet<Integer>(); // 停顿词
private static final char SIGN = '*'; // 敏感词过滤替换
static {
try {
long a = System.nanoTime();
init();
a = System.nanoTime() - a;
System.out.println("加载时间 : " + a + "ns");
System.out.println("加载时间 : " + a / 1000000 + "ms");
} catch (Exception e) {
throw new RuntimeException("初始化过滤器失败");
}
}
private static void init() {
// 获取敏感词
addSensitiveWord(readWordFromFile("wd.txt"));
addStopWord(readWordFromFile("stopwd.txt"));
}
/**
* 增加敏感词
*/
private static List<String> readWordFromFile(String path) {
List<String> words;
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(WordFilter.class.getClassLoader().getResourceAsStream(path)));
words = new ArrayList<String>(1200);
for (String buf = ""; (buf = br.readLine()) != null;) {
if (buf == null || buf.trim().equals(""))
continue;
words.add(buf);
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (br != null)
br.close();
} catch (IOException e) {
}
}
return words;
}
/**
* 增加停顿词
*/
private static void addStopWord(final List<String> words) {
if (words != null && words.size() > 0) {
char[] chs;
for (String curr : words) {
chs = curr.toCharArray();
for (char c : chs) {
stopwdSet.add(charConvert(c));
}
}
}
}
/**
* 添加DFA节点
*/
private static void addSensitiveWord(final List<String> words) {
if (words != null && words.size() > 0) {
char[] chs;
int fchar;
int lastIndex;
WordNode fnode; // 首字母节点
for (String curr : words) {
chs = curr.toCharArray();
fchar = charConvert(chs[0]);
if (!set.contains(fchar)) {// 没有首字定义
set.add(fchar);// 首字标志位 可重复add
fnode = new WordNode(fchar, chs.length == 1);
nodes.put(fchar, fnode);
} else {
fnode = nodes.get(fchar);
if (!fnode.isLast() && chs.length == 1)
fnode.setLast(true);
}
lastIndex = chs.length - 1;
for (int i = 1; i < chs.length; i++) {
fnode = fnode.addIfNoExist(charConvert(chs[i]), i == lastIndex);
}
}
}
}
/**
* 过滤判断 将敏感词转化为成屏蔽词
*/
public static final String doFilter(final String src) {
char[] chs = src.toCharArray();
int length = chs.length;
int currc;
int k;
WordNode node;
for (int i = 0; i < length; i++) {
currc = charConvert(chs[i]);
if (!set.contains(currc)) {
continue;
}
node = nodes.get(currc);
if (node == null)
continue;
boolean couldMark = false;
int markNum = -1;
if (node.isLast()) {
couldMark = true;
markNum = 0;
}
k = i;
for (; ++k < length;) {
int temp = charConvert(chs[k]);
if (stopwdSet.contains(temp))
continue;
node = node.querySub(temp);
if (node == null)
break;
if (node.isLast()) {
couldMark = true;
markNum = k - i;
}
}
if (couldMark) {
for (k = 0; k <= markNum; k++) {
chs[k + i] = SIGN;
}
i = i + markNum;
}
}
return new String(chs);
}
/**
* 是否包含敏感词
*/
public static final boolean isContains(final String src) {
char[] chs = src.toCharArray();
int length = chs.length;
int currc;
int k;
WordNode node;
for (int i = 0; i < length; i++) {
currc = charConvert(chs[i]);
if (!set.contains(currc)) {
continue;
}
node = nodes.get(currc);
if (node == null)
continue;
boolean couldMark = false;
if (node.isLast()) {
couldMark = true;
}
k = i;
for (; ++k < length;) {
int temp = charConvert(chs[k]);
if (stopwdSet.contains(temp))
continue;
node = node.querySub(temp);
if (node == null)
break;
if (node.isLast()) {
couldMark = true;
}
}
if (couldMark) {
return true;
}
}
return false;
}
/**
* 大写转化为小写 全角转化为半角
*/
private static int charConvert(char src) {
int r = BCConvert.qj2bj(src);
return (r >= 'A' && r <= 'Z') ? r + 32 : r;
}
}
WordFilter.java
其中:
isContains :是否包含敏感词
doFilter:过滤敏感词
2、WordNode敏感词节点:
package com.skyer.sensitivewdfilter;
import java.util.LinkedList;
import java.util.List;
public class WordNode {
private int value; // 节点名称
private List<WordNode> subNodes; // 子节点
private boolean isLast; // 默认false
public WordNode(int value) {
this.value = value;
}
public WordNode(int value, boolean isLast) {
this.value = value;
this.isLast = isLast;
}
/**
* @return 就是传入的subNode
*/
private WordNode addSubNode(final WordNode subNode) {
if (subNodes == null)
subNodes = new LinkedList<WordNode>();
subNodes.add(subNode);
return subNode;
}
/**
* 有就直接返回该子节点, 没有就创建添加并返回该子节点
*/
public WordNode addIfNoExist(final int value, final boolean isLast) {
if (subNodes == null) {
return addSubNode(new WordNode(value, isLast));
}
for (WordNode subNode : subNodes) {
if (subNode.value == value) {
if (!subNode.isLast && isLast)
subNode.isLast = true;
return subNode;
}
}
return addSubNode(new WordNode(value, isLast));
}
public WordNode querySub(final int value) {
if (subNodes == null) {
return null;
}
for (WordNode subNode : subNodes) {
if (subNode.value == value)
return subNode;
}
return null;
}
public boolean isLast() {
return isLast;
}
public void setLast(boolean isLast) {
this.isLast = isLast;
}
@Override
public int hashCode() {
return value;
}
}
WordNode.java
3、测试类:
package com.skyer.test;
import org.junit.Test;
import com.skyer.sensitivewdfilter.WordFilter;
public class TestSensitivewd {
@Test
public void TestFilter() {
String s = ""; // 这里写你要过滤的句子(我这里不能写,否则会给博客园屏蔽掉)
System.out.println("解析问题: " + s);
System.out.println("解析字数 : " + s.length());
String re;
long nano = System.nanoTime();
re = WordFilter.doFilter(s);
nano = (System.nanoTime() - nano);
System.out.println("解析时间 : " + nano + "ns");
System.out.println("解析时间 : " + nano / 1000000 + "ms");
System.out.println(re);
System.out.println();
nano = System.nanoTime();
System.out.println("是否包含敏感词: " + WordFilter.isContains(s));
nano = (System.nanoTime() - nano);
System.out.println("解析时间 : " + nano + "ns");
System.out.println("解析时间 : " + nano / 1000000 + "ms");
}
}
TestSensitivewd.java
4、测试结果:

原文参考:http://blog.csdn.net/fengshizty/article/details/52373005
DFA知识:http://www.cnblogs.com/naaoveGIS/archive/2016/10/14/5960352.html
使用DFA算法对敏感词进行过滤的更多相关文章
- DFA算法实现敏感词过滤
DFA算法:即确定有穷自动机,简单点说就是,它是是通过event和当前的state得到下一个state,即event+state=nextstate.理解为系统中有多个节点,通过传递进入的event, ...
- Java 利用DFA算法 屏蔽敏感词
原文:http://www.open-open.com/code/view/1435214601278 import java.io.BufferedReader; import java.io.Fi ...
- 如何用Python实现敏感词的过滤
题目要求如下: 从文件解析敏感词,从终端获取用户输入.根据敏感词对用户输入进行过滤.这里过滤需要考虑不止一个过滤词:即将读取的所有过滤词,放进一个列表,用屏蔽词检索用户输入,如果有屏蔽词,则将其替换为 ...
- Java实现敏感词过滤 - DFA算法
Java实现DFA算法进行敏感词过滤 封装工具类如下: 使用前需对敏感词库进行初始化: SensitiveWordUtil.init(sensitiveWordSet); package cn.swf ...
- 敏感词过滤的算法原理之DFA算法
参考文档 http://blog.csdn.net/chenssy/article/details/26961957 敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有 ...
- DFA和trie特里实现敏感词过滤(python和c语言)
今天的项目是与完成python开展,需要使用做关键词检查,筛选分类,使用前c语言做这种事情.有了线索,非常高效,内存小了,检查快. 到达python在,第一个想法是pip基于外观的c语言python特 ...
- Java实现敏感词过滤
敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来 ...
- Java实现敏感词过滤(转)
敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来 ...
- Jsp敏感词过滤
Jsp敏感词过滤 大部分论坛.网站等,为了方便管理,都进行了关于敏感词的设定. 在多数网站,敏感词一般是指带有敏感政治倾向(或反执政党倾向).暴力倾向.不健康色彩的词或不文明语,也有一些网站根据自身实 ...
随机推荐
- Shiro基础学习(一)—权限管理
一.基本概念 1.权限管理 只要有用户参与的系统一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源. 权限管理 ...
- JDBC基础学习(五)—批处理插入数据
一.批处理介绍 当需要成批插入或者更新记录时.可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理.通常情况下比单独提交处理更有效率. JDBC的批量处理语句包括下 ...
- 微信小程序,前端大梦想(三)
微信小程序的事件及生命周期 继续下节课,今天我们还是从四个方面来了解小程序: ●常用事件和事件冒泡 ●配置 ●app生命周期及app对象的使用 ●页面的生命周期 一.事件的 ...
- ios sqlite3的简单使用
第一:创建表格 //创建表格 -(void)creatTab{ NSString*creatSQL=@"CREATE TABLE IF NOT EXISTS PERSIONFO(ID INT ...
- kafka分布式消息队列介绍以及集群安装
简介 首先简单说下对kafka的理解: 1.kafka是一个分布式的消息缓存系统: 2.kafka集群中的服务器节点都被称作broker 3.kafka的客户端分为:一是producer(消息生产者) ...
- Linux:一位猫奴的意外产物
作者:Vamei,严禁任何形式转载. 1991年年中,林纳斯·托瓦兹(Linus Torvalds)在自己房间里敲着键盘.他全神贯注地盯着14寸的黑色屏幕,都没感觉到自己的小猫Randi在扒自己的裤腿 ...
- css系列(布局):实现一个元素在浏览器中水平、垂直居中的几个方案
在开发中偶遇需要一个元素垂直居中的需求,之前都是水平居中,垂直居中使用的比较少,经过一通研究,选择了几种相对比较实用的方案分享,抛砖引玉,如有遗漏不足,还望不吝指正. 方案一(IE7下该方案无法实现垂 ...
- python在cmd上导包成功,但是python charm上面就提示找不到
失败 成功 原因:我的python file名称和numpy 的名字一样了,把python file 的名字改了就好了
- 记录一个NPE问题
昨天在做公司项目时,我在一处地方加了一个逻辑校验,之后测了下发现在方法调用深处有一处NPE,来源于另一个同事的代码. 其实NPE本应该是个Java编程中老掉牙的问题,但我觉得这一处错误还是比较典型的, ...
- Rookey.Frame v1.0 视频教程发布了
经过昨天几个小时的折腾, Rookey.Frame v1.0开发视频教程终于发布了,由于是第一次做视频有很多地方做的不够好,后续我会慢慢改进,争取将视频教程做好. 本期发布视频: (一)Rookey. ...