文档章节

java --敏感词汇过滤

求是科技
 求是科技
发布于 2016/09/29 18:14
字数 1559
阅读 82
收藏 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
**丰**毛**怪

© 著作权归作者所有

共有 人打赏支持
求是科技
粉丝 89
博文 456
码字总数 228627
作品 0
成都
后端工程师
Apache Lucene 几种分词系统

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

6pker
2015/02/26
0
0
centos 搭建openfire 结合ldap

1.先确定linux自带的jdk是否安装,卸载安装的 java --sersion 查看java版本信息 rpm -qa |grep java 查找已经安装的java 如果有则使用rpm -e --nodeps 卸载 rpm -qa |grep gcj rpm -qa |gre...

xucaibao1979
06/28
0
0
设置 java -jar 的进程显示名称

有时候我们会用 nohup java -jar xxx.jar来将一些可执行的java application挂在后台,类似windows服务一样来运行。但是有一个不爽的地方,在linux终端里用jps显示时,全都显示成jar,如下图所...

闪电
2015/09/02
0
0
最近使用logstash遇到的问题(关于数据导入)

要求通过logstash从oracle中获取数据,然后相应的直接传入mysql中去。 基本测试成功的配置文件如下: input {    stdin {   }   jdbc {   jdbcconnectionstring => "jdbc:oracle:th...

&Legend
08/05
0
0
-1-0 Java 简介 java是什么 java简单介绍

Java是一门纯粹的面向对象的高级的平台无关的编程语言 官网介绍: 了解 Java 技术 https://www.java.com/zh_CN/about/ 推荐词条: https://zh.wikipedia.org/wiki/Java https://zh.wikipedia.o...

noteless
07/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Python介绍

Python介绍 一、简介 Python是完全面向对象的语言。函数、模块、数字、字符串都是对象。并且完全支持继承、重载等,有益于增强源代码的复用性。Python相对于Lisp这种传统的函数式编程语言,P...

星汉
32分钟前
1
0
VS_设置护眼背景色

工具---->选项---->环境---->字体和颜色:

一个小妞
35分钟前
0
0
Flask跨域请求的处理方法

在Flask开发RESTful后端时,前端请求会遇到跨域的问题。下面是解决方法: 使用 flask-cors库可以很容易的解决 pip install flask-cors 两种方法,一个是全局/批量的,一个是单一独立的: 安全...

ykbj
36分钟前
9
0
Pandas学习记录-Series

系列(Series)是能够保存任何类型的数据(整数,字符串,浮点数,Python对象等)的一维标记数组。轴标签统称为索引。 pandas.Series Pandas系列可以使用以下构造函数创建 - pandas.Series( dat...

kipeng300
43分钟前
1
0
可以实现内网穿透的几款工具

最近没什么事情,看了一些关于内网穿透的文章,因我本身已是做微信开发相关的工作,对这部分关注的比较多,现分享给大家。 首先说下内网穿透的原理。 NAPT原理 在NAT网关上会有一张映射表,表...

哥本哈根的小哥
45分钟前
38
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部