关于java中敏感词检测的一些总结

之前项目里客户提出一个需求,需要对系统中使用文本转化成语音发送的功能进行敏感词检测,禁止用户提交有敏感词的语音。通过查询各方面资料,整理了大概几种方案:

  1. 项目启动时对载入敏感词库作为缓存(一个大map,敏感词为key,取任意值为value)。 对请求传入的文本分词,遍历分词结果,每个分词在map中查找,如果有值,则请求文本存在敏感词。
  2. 把敏感词库拼接成一个大的正则表达式,然后直接对文本匹配。
  3. 使用DFA(确定性有限状态自动机) DFA算法

对于方案选择,在网上参考了很多别人的代码。最简单的是方法2使用正则表达式,但是据说文本一长会有很大的效率问题。关于方法3DFA算法,由于在学校的时候算法课和编译原理没有认真听讲(惭愧= =||),直接就忽略这方法了,所以最后还是决定使用方法1。
其实方法1还是有很多可以改进的方法,后来又参考了这个帖子12楼中的方法,使用索引数组加关联数组的方式,提高了检索效率,甚至连分词的步骤都省掉了。整个实现代码如下。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import org.apache.commons.lang.StringUtils;
  
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
  
import java.io.IOException;
  
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
  
  
/**
* User: eternity
* Date: 2014/8/11
* Time: 16:17
* 敏感词检测类
* 敏感词检测初始化规则:
* 将敏感词从词库载入,按照2字、3字、4字、5字等字数各生成一个敏感词哈希表。
* 在将这些哈希表组成一个数组banWordsList,数组下标表示该敏感词表字数
* banWordsList[2] = {某马:true,屏蔽:true,啦啦:true};
* banWordsList[3] = {某个马:true,三个字:true,啦啦啦:true,小广告:true};
* banWordsList[4] = {某个坏银:true,四个字符:true,哈哈哈哈:true,就爱凤姐:true};
* banWordsList[5] = {某个大法好:true,五个敏感字:true};
* 根据上面几组组敏感词,自动生成以下索引
* 生成规则为,索引名是敏感词第一个字,值是一个int
* 该int的规则为,该int转换成二进制时,第i位为1表示上面4表存在长度为i的敏感词,否则不存在长度为i的敏感词(10000)
* wordIndex = {二:0x04,三:0x08,四:0x10,五:0x20,某:0x3c,啦:0x0c,哈:0x10,小:0x08,就:0x10};
*
* 检查规则如下:
* 1,逐字检验,是否该字在wordIndex索引表中。
* 2,如果不在表中,继续检验
* 3,如果在表中,根据索引表该键的值,取此字以及此字后的若干字检验详细表banWordsList[索引词长]。
*
* 检验例子
* 有一段如下文字,检验其是否包含敏感词:
“我就打小广告,气死版主”
——检测“我”
|-不在索引表
——检测“就”
|-在索引表
|-“就”的索引值是0x10,表示有4字以“就”开头的敏感词
|-取“就”和后面的字共4个,组成“就打小广”
|-查4字敏感词表,没有这项,继续
——检测“打”
|-不在索引表
——检测“小”
|-在索引表
|-索引值是0x08,表示有3字长度的敏感词
|-取“小”和“小”后面的字,共3个字组成一个词“小广告”
|-“小广告”在3字敏感词中,此帖包含敏感词,禁止发布
*/
public class BanWordsUtil {
     // public Logger logger = Logger.getLogger(this.getClass());
     public static final int WORDS_MAX_LENGTH = 10 ;
     public static final String BAN_WORDS_LIB_FILE_NAME = "banWords.txt" ;
  
     //敏感词列表
     public static Map[] banWordsList = null ;
  
     //敏感词索引
     public static Map<String, Integer> wordIndex = new HashMap<String, Integer>();
  
     /*
     * 初始化敏感词库
     */
     public static void initBanWordsList() throws IOException {
         if (banWordsList == null) {
             banWordsList = new Map[WORDS_MAX_LENGTH];
  
             for (int i = 0; i < banWordsList.length; i++) {
                 banWordsList[i] = new HashMap<String, String>();
             }
         }
  
         //敏感词词库所在目录,这里为txt文本,一个敏感词一行
         String path = BanWordsUtil.class.getClassLoader()
                                         .getResource(BAN_WORDS_LIB_FILE_NAME)
                                         .getPath();
         System.out.println(path);
  
         List<String> words = FileUtils.readLines(FileUtils.getFile(path));
  
         for (String w : words) {
             if (StringUtils.isNotBlank(w)) {
                 //将敏感词按长度存入map
                 banWordsList[w.length()].put(w.toLowerCase(), "");
  
                 Integer index = wordIndex.get(w.substring(0, 1));
  
                 //生成敏感词索引,存入map
                 if (index == null) {
                     index = 0;
                 }
  
                 int x = (int) Math.pow(2, w.length());
                 index = (index | x);
                 wordIndex.put(w.substring(0, 1), index);
             }
         }
     }
  
     /**
     * 检索敏感词
     * @param content
     * @return
     */
     public static List<String> searchBanWords(String content) {
         if (banWordsList == null ) {
             try {
                 initBanWordsList();
             } catch (IOException e) {
                 throw new RuntimeException(e);
             }
         }
  
         List<String> result = new ArrayList<String>();
  
         for ( int i = 0 ; i < content.length(); i++) {
             Integer index = wordIndex.get(content.substring(i, i + 1 ));
             int p = 0 ;
  
             while ((index != null ) && (index > 0 )) {
                 p++;
                 index = index >> 1 ;
  
                 String sub = "" ;
  
                 if ((i + p) < (content.length() - 1 )) {
                     sub = content.substring(i, i + p);
                 } else {
                     sub = content.substring(i);
                 }
  
                 if (((index % 2 ) == 1 ) && banWordsList[p].containsKey(sub)) {
                     result.add(content.substring(i, i + p));
  
                     // System.out.println("找到敏感词:"+content.substring(i,i+p));
                 }
             }
         }
  
         return result;
     }
  
     public static void main(String[] args) throws IOException {
         String content = "含有敏感词的测试语句。" ;
         BanWordsUtil.initBanWordsList();
         List<String> banWordList = BanWordsUtil.searchBanWords(content);
         for (String s : banWordLis){
          System.out.println( "找到敏感词:" +s);
         }
     }
}
上面测试语文本里面其实没有敏感词(我也怕被屏蔽XD),测试的时候随便加入几个敏感词都能检测出来的。这样就实现了一个简易又快速的敏感词检测,当然如果有需要比较复杂的检测逻辑(比如说“弹吉他妈妈真漂亮”这样的),还是要用到分词工具把词拆分一下的。

来自:http://my.oschina.net/u/1010578/blog/308904
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 敏感词检测可以通过多种方式实现,以下是一种简单的方法: 1. 构建敏感词库:将敏感词以数组、列表或哈希表的形式存储起来。可以手动添加敏感词,也可以从文件或数据库加载。 2. 实现敏感词检测方法:编写一个方法,接受待检测的文本作为参数,返回是否包含敏感词。 3. 遍历文本:将待检测的文本按字符或单词进行遍历。 4. 匹配敏感词:对于每个字符或单词,与敏感词敏感词逐一比较。可以使用字符串匹配算法,如KMP算法或AC自动机算法,提高匹配效率。 5. 返回结果:如果匹配到敏感词,则返回true;否则,返回false。 下面是一个简单的示例代码: ```java import java.util.ArrayList; import java.util.List; public class SensitiveWordFilter { private List<String> sensitiveWords; public SensitiveWordFilter() { sensitiveWords = new ArrayList<>(); // 添加敏感词敏感词库 sensitiveWords.add("敏感词1"); sensitiveWords.add("敏感词2"); sensitiveWords.add("敏感词3"); } public boolean hasSensitiveWord(String text) { for (String word : sensitiveWords) { if (text.contains(word)) { return true; } } return false; } public static void main(String[] args) { SensitiveWordFilter filter = new SensitiveWordFilter(); String text = "这是一段包含敏感词的文本"; boolean hasSensitiveWord = filter.hasSensitiveWord(text); System.out.println("是否包含敏感词:" + hasSensitiveWord); } } ``` 这只是一个简单的实现,实际应用可能需要处理更复杂的情况,如多个敏感词之间的空格、大小写等。可以根据具体需求进行适当修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值