文档章节

java --敏感词汇过滤

求是科技
 求是科技
发布于 2016/09/29 18:14
字数 1559
阅读 91
收藏 3

每个app的评论(或提问等)功能都会做敏感词过滤。
#1.常规做法

	/**
	 * flag:0(不是敏感词) 1(敏感词)
	 */
	public int checkWord() {
		int flag = 0;		
		String content = "用户评论的内容";
		java.util.List<String> list = new ArrayList<>();
		//从数据库取出敏感词汇列表
		list.add("习dd");
		list.add("彭mm");
		list.add("网络流行语");
		
		for (int i = 0; i < list.size(); i++) {
			if (content.contains(list.get(i))) {
				flag = 1;
				break;
			}
		}
		return flag;
	}

当数据量很大的时候,如上的方法执行效率特别慢,因此需要找改进的方法,如下有一篇文章写的不错
http://www.cnblogs.com/chenssy/p/3751221.html#2966041
#2.改进方法
将敏感词加入到HashMap中,构建DFA算法模型

public class SensitiveWordInit {
	
	/**
	 * @Description: 初始化敏感词库,将敏感词加入到HashMap中,构建DFA算法模型
	 * @param list:从数据库获取到的敏感词汇列表
	 * @return 敏感词汇HashMap
	 * 备注:原作者的入参是Set<String>,我改成了List.
	 * 改完后才发现作者的用心,Set的效率比List高
	 */
	public HashMap getSensitiveWordToHashMap(List<String> list){
		
		//敏感词汇map
		HashMap sensitiveWordMap = new HashMap<>();
		//关键字
		String key = "";
		//转换map
		Map tempMap = null;
		//给临时map赋值
		Map newMap = null;
		
		//迭代器
		Iterator<String> it = list.iterator();
		while (it.hasNext()) {
			//取出关键词
			key = it.next();
			//这里给输出map赋值
			tempMap = sensitiveWordMap;
			
			//拆分关键词,存入map
			for (int i = 0; i < key.length(); i++) {
				//由于key是字符串型,所以里面存放的是字符型,因此存在如下取法
				//备注:其实这里可以将key转成array,用array[i]取还是一样
				char keyChar = key.charAt(i);
				
				//从转换map里面取出单个"关键字",多个关键字组成关键词
				//备注:这里可以使用String类型来接收
				Object tmpKey = tempMap.get(keyChar);
				//如果tmpKey里面存在该key,直接赋值
				if (tmpKey != null) {
					tempMap = (Map)tmpKey;
				}else
				{
					/**
					 * 如果不存在该key,则添加进去
					 */
					//新构建一个map,将isEnd设值0,因为它不是最后一个
					newMap = new HashMap<>();
					//不是最后一个
					newMap.put("isEnd", 0);
					//将该key添加到tempMap,实际上是添加到sensitiveWordMap中
					//这里涉及到一个地址引用的知识点
					tempMap.put(keyChar, newMap);
					//重新使tempMap指向newMap
					tempMap = newMap;
				}
				//最后一个
				if(i == key.length() - 1){
					tempMap.put("isEnd", "1");    
				}
			}
		}
		
		//返回敏感词汇map
		return sensitiveWordMap;
	}
}

敏感词汇过滤类

/**
 * 敏感词汇过滤类
 * 包含三个主要方法
 * 1.isContaintSensitiveWord,判断输入的内容是不是包含敏感词汇
 * 2.getSensitiveWord,获取输入内容的敏感词
 * 3.replaceSensitiveWord,替换敏感词汇字符
 */
public class SensitiveWordFilter {
	
	//敏感词汇map
	private HashMap sensitiveWordMap;
	//最小匹配规则
	//一旦匹配到,不继续匹配,直接返回
	private static int minMatchTYpe = 1;
	//最大匹配规则
	//匹配所有的
	private static int maxMatchType = 2;
	//关键词汇集合
	public List<String> list = new ArrayList<>();
	
	
	/**
	 * 构造函数,初始化敏感词汇库
	 * @param list
	 */
	public SensitiveWordFilter(List<String> list) {
		sensitiveWordMap = new SensitiveWordInit().getSensitiveWordToHashMap(list);
	}
	
	/**
	 * 判断输入的内容是不是包含敏感词汇
	 * @param content:输入的内容
	 * @param matchType:匹配规则
	 * @return true or false
	 */
	public boolean isContaintSensitiveWord(String content,int matchType){
		boolean flag = false;
		
		for (int i = 0; i < content.length(); i++) {
			//循环匹配
			int matchFlag = CheckSensitiveWord(content, i, matchType);
			//大于0存在,返回true
			if(matchFlag > 0){    
				flag = true;
			}
		}
		
		return flag;
	}
	/**
	 * 获取输入内容的敏感词
	 * @param content:输入内容
	 * @param matchType:匹配类型
	 * @return 匹配到的敏感词列表
	 */
	public List<String> getSensitiveWord(String content,int matchType){
		List<String> sensitiveWordList = new ArrayList<>();
		
		//判断是否存在敏感词汇,不存在为0
		int length = 0;
		for (int i = 0; i < content.length(); i++) {
			//判断是否包含敏感词汇
			length = CheckSensitiveWord(content, i, matchType);
			//如果存在
			if (length > 0) {
				//截取输入内容的i到i+length
				sensitiveWordList.add(content.substring(i, i+length));
				//减1的原因,是因为for会自增
				/**
				 * 举例:假设i从0开始,length=5,则匹配了0~4共5个字符
				 * 因此,下一次匹配时,i应该从5开始
				 * 注意:这一次匹配完了之后,会执行i++,因此i++的值应该是5
				 * 所以这里需要将i的值设成0+5-1=4
				 * 这一次执行完了后,i的值变成5
				 */
				i = i + length - 1;
			}
		}
		return sensitiveWordList;
	}
	
	/**
	 * 替换敏感词汇字符
	 * @param content:输入的内容
	 * @param matchType:匹配规则
	 * @param replaceChar:替换字符,例如:*
	 * @return 输入字符串,敏感词汇被替换成*
	 */
	public String replaceSensitiveWord(String content,int matchType,String replaceChar){
		String resultTxt = content;
		//获取所有的敏感词汇
		List<String> replaceSensitiveWordList = getSensitiveWord(content, matchType);
		//临时变量
		String word = null;
		//替换字符串
		String replaceString = null;
		//迭代器
		Iterator<String> it = replaceSensitiveWordList.iterator();
		while (it.hasNext()) {
			//敏感词汇(多个字符,假设5个字符)
			word = it.next();
			//这是替换后的字符(假设5个)
			replaceString = getReplaceChars(replaceChar, word.length());
			//替换后的字符串
			resultTxt = resultTxt.replaceAll(word, replaceString);
		}
		
		return resultTxt;
	}
	
	/**
	 * 获取替换字符串
	 * @param replaceChar:替换成什么字符,例如:*
	 * @param length:需要将几个字符替换成*
	 * @return 多少个*
	 */
	private String getReplaceChars(String replaceChar,int length){
		String resultReplace = replaceChar;
		for(int i = 1 ; i < length ; i++){
			resultReplace += replaceChar;
		}
		return resultReplace;
	}
	
	/**
	 * 检查输入内容是否包含敏感词汇
	 * @param content:输入内容
	 * @param beginIndex:匹配位置
	 * @param matchType:匹配规则
	 * @return true or false
	 */
	public int CheckSensitiveWord(String content,int beginIndex,int matchType){
		
		//敏感词汇结束标识符,默认为没有匹配到
		boolean  flag = false;
		//匹配到敏感词汇的次数
		int matchFlag = 0;
		//临时变量
		char word = 0;
		Map tmpMap = sensitiveWordMap;
		for (int i = beginIndex; i < content.length(); i++) {
			//取出输入内容的字符
			word = content.charAt(i);
			//获取key
			tmpMap = (Map) tmpMap.get(word);
			//如果存在
			if (tmpMap != null) {
				//匹配标识加1
				matchFlag++;
				//匹配到了最后,结束循环,返回匹配数
				if ("1".equals(tmpMap.get("isEnd"))) {
					//结束标志位为true 
					flag = true;
					//最小规则,退出for循环;最大规则,继续for循环
					if (SensitiveWordFilter.minMatchTYpe == matchType) {
						break;
					}
				}
			}else
			{
				//不存在,直接退出for循环
				break;
			}
		}
		//词至少由两个字符组成
		//1.仅仅匹配到单个字符,它不能构成词,因此匹配失败
		//2.flag=false,说明匹配失败
		if (matchFlag < 2 || !flag) {
			matchFlag = 0;
		}
		return matchFlag;
	}
	
	//测试
	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		list.add("张三");
		list.add("李四");
		list.add("王五");
		list.add("赵六");
		SensitiveWordFilter swf = new SensitiveWordFilter(list);
		System.out.println("敏感词的数量:" + swf.sensitiveWordMap.size());
		//输入字符串
		String content = "张三丰李四毛王五怪";
		//测试1:匹配输出所有的关键词(最小匹配规则)
		List<String> list2 = swf.getSensitiveWord(content, 1);
		System.out.println(list2);
		//测试2:isContaintSensitiveWord
		boolean exite = swf.isContaintSensitiveWord(content, 1);
		System.out.println(exite);
		//测试3:将敏感词汇替换成*
		String replaceString = swf.replaceSensitiveWord(content, 1, "*");
		System.out.println(replaceString);
	}
}

测试结果

敏感词的数量:4
[张三, 李四, 王五]
true
**丰**毛**怪

© 著作权归作者所有

共有 人打赏支持
求是科技
粉丝 91
博文 439
码字总数 226317
作品 0
成都
后端工程师
私信 提问
有个问题请教红薯老大下

老大,最近有个项目对 信息内容 的控制比较严格,对一些敏感词要进行过滤, 我有个模糊的印象 在论坛里看到过该类问题的贴子,找不到了,希望老大能分享下 敏感词过滤的实现思路(Java),或...

慢慢爬
2011/03/04
153
2
Apache Lucene 几种分词系统

1、 StopAnalyzer StopAnalyzer能过滤词汇中的特定字符串和词汇,并且完成大写转小写的功能。 2、 StandardAnalyzer StandardAnalyzer根据空格和符号来完成分词,还可以完成数字、字母、E-m...

6pker
2015/02/26
0
0
开源了一个 Javascript 版敏感词过滤库

最近在做一个项目,寻遍了 Node 开源社区居然没有发现一个好用的敏感词过滤库,有那么几个库外观上看起来似乎还不错,用起来却一塌糊涂,震惊有余,失望至极。于是花了一天时间自己撸了一个库...

老錢
10/25
0
0
[转贴] Lucene 3.0 的几种分词系统

1、 StopAnalyzer StopAnalyzer能过滤词汇中的特定字符串和词汇,并且完成大写转小写的功能。 2、 StandardAnalyzer StandardAnalyzer根据空格和符号来完成分词,还可以完成数字、字母、E-m...

红薯
2010/10/20
6.5K
3
java+html实现弹幕功能并集成敏感词过滤功能,实现思路

即时评论和即时弹幕功能架构设计: 后端数据存储 前端弹幕展示方式 前后台即时通讯方式 敏感词过滤系统 数据存储 弹幕数据庞大,一般是无用数据,存储的话纯文本就行,结构化要求不强,数据不...

两毛五哥哥
2017/11/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

自定义 Maven 的 repositories

有时,应用中需要一些比较新的依赖,而这些依赖并没有正式发布,还是处于milestone或者是snapshot阶段,并不能从中央仓库或者镜像站上下载到。此时,就需要 自定义Maven的<repositories>。 ...

waylau
49分钟前
1
0
徒手写一个es6代码库

mkdir democd demonpm initnpm install -g babelnpm install -g babel-clinpm install --save-dev babel-preset-es2015-node5 在项目目录创建两个文件夹 functional-playground ......

lilugirl
49分钟前
2
0
linux定位应用问题的一些常用命令,特别针对内存和线程分析的dump命令

1.jps找出进程号,找到对应的进程号后面才好继续操作 2.linux查看进程详细信息 ps -ef | grep 进程ID 3. dump内存信息 Jmap -dump:format=b,file=YYMMddhhmm.dump pid 4.top查看cpu占用信息 ...

noob_chr
49分钟前
1
0
Android TV开发-按键焦点

写在前面 按键焦点过程了解 2.1 dispatchKeyEvent 过程了解 2.2 焦点查找请求过程了解 1.2.1 第一次获取焦点 1.2.3 按键焦点 焦点控制 焦点记忆 应用场景 参考资料 [TOC] 1. 写在前面 工...

冰雪情缘l
49分钟前
1
0
java框架学习日志-3

这章主要是补充一些ioc创建对象的方式,ioc容器在写好<bean></bean>的时候就已经创建对象了。在之前的例子中,一直都是无参的构造方法。下面给出有参的构造方法的对象的创建,没有什么难点重...

白话
52分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部