该算法往往是用于匹配一些敏感词、绝对词等,从一篇文章中快速找到其中包含的关键词。
实现思路:
先读取所有关键词并存入set集合中。再将set中的关键词存入HashMap中,是以每个关键词字顺序存储,key为一个字、value为一个HashMap。在每一个HashMap都有一个key为is_end键值对来代表该字之前是否为一个关键词。
大致存储结构如下:
以此为例(最先、最先进、最先进科技、最先进工艺、全球、全国)
首先存储这些关键词
/**
* @author CC
* @version 1.0
* @since2023/11/7
*/
public class SensitiveWordMap {
private static final String ENCODING = "utf-8";
public static final String IS_END_KEY ="is_end";
// 初始化敏感字库
public Map initKeyWord() throws IOException {
Set<String> set = readSensitiveWordFile();
Map<String, Object> stringObjectMap = addSensitiveWordToHashMap(set);
return stringObjectMap;
}
// 读取敏感词库,存入Set中
private Set<String> readSensitiveWordFile() throws IOException {
Set<String> wordSet =null;
//通过txt文件获取所有关键词并存入set集合中
try (InputStream inputStream = SensitiveWordMap.class.getResourceAsStream("/static/words.txt");
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, ENCODING);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);) {
wordSet =new HashSet<String>();
String line =null;
while ((line=bufferedReader.readLine())!=null){
wordSet.add(line);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return wordSet;
}
// 将Set中的敏感词,存入HashMap中
private Map<String, Object> addSensitiveWordToHashMap(Set<String> wordSet) {
//初始化词库Map
Map<String,Object> wordMap =new HashMap<>();
//遍历关键词库中的每个关键词
for (String word:wordSet){
Map<String, Object> nowMap =wordMap;
//遍历每个关键词的每个字
for (int i = 0; i <word.length() ; i++) {
//关键词中的某个字
String keyChar =String.valueOf(word.charAt(i));
Map<String,Object> subWordMap = (Map<String, Object>) nowMap.get(keyChar);
if (subWordMap==null){
subWordMap=new HashMap<>();
subWordMap.put(IS_END_KEY,false);
nowMap.put(keyChar,subWordMap);
}
//切换下一层
nowMap=subWordMap;
//判断当前“字”是否是关键词的最后一个字
if (i==word.length()-1){
nowMap.put(IS_END_KEY,true);
}
}
}
return wordMap;
}
}
words.txt如下
最佳 最具 最爱 最佳 最优 最优秀 最大 最大程度 最高 最高级 最高档 最高阶 最奢侈 最低 最低级 最低价 最先 最先进 最先进科技 最先进工艺 最先享受 最新 最新科技 最新理念
匹配关键词类
/**
* @author CC
* @version 1.0
* @since2023/11/7
*/
public class SensitiveFilter {
/**
* 敏感词过滤器:利用DFA算法 进行敏感词过滤
*/
private Map sensitiveWordMap = null;
/**
* 最小匹配规则,
* 例如:敏感词库["最先","最先进","最先进工艺"],
* 语句:"机身采用最先进工艺打造",
* 匹配结果:[最先]
*/
public static final int MIN_MATCH_TYPE = 1;
/**
* 最大匹配规则,
* 例如:敏感词库["最先","最先进","最先进工艺"],
* 语句:"机身采用最先进工艺打造",
* 匹配结果:[最先进工艺]
*/
public static final int MAX_MATCH_TYPE = 2;
// 单例
private static SensitiveFilter instance = null;
/**
* 构造函数,初始化敏感词库
*/
private SensitiveFilter() throws IOException {
SensitiveWordMap wordMap = new SensitiveWordMap();
sensitiveWordMap = wordMap.initKeyWord();
}
/**
* 获取单例
*/
public static SensitiveFilter getInstance() throws IOException {
if (instance == null) {
instance = new SensitiveFilter();
}
return instance;
}
/**
* 获取文字中的敏感词
*/
public Set<String> getSensitiveWord(String txt, int matchType) {
Set<String> set =new HashSet<>();
for (int i = 0; i <txt.length() ; i++) {
int count = checkSensitiveWord(txt, i, matchType);
if (count!=0){
set.add(txt.substring(i,count+i));
i=i+count-1;
}
}
return set;
}
/**
* 检查文字中是否包含敏感字符,检查规则如下:
* 如果存在,则返回敏感词字符的长度
* 如果不存在,返回0
*/
private int checkSensitiveWord(String txt, int beginIndex, int matchType) {
//关键词库
Map<String, Object> nowMap = sensitiveWordMap;
//记录匹配标志次数
int matchFlag = 0;
//结束标志
boolean flag = false;
//从指定位置开始遍历“关键字“字符串
for (int i = beginIndex; i < txt.length(); i++) {
//获取一个字
String keyChar = String.valueOf(txt.charAt(i));
//根据当前关键”字“,从词库中获取该”关键字“对应的map
nowMap = (Map<String, Object>) nowMap.get(keyChar);
if (nowMap != null) {
//匹配成功
matchFlag++;
if ((boolean) nowMap.get(SensitiveWordMap.IS_END_KEY)) {
//代表本次匹配状态终止
flag = true;
//如果匹配规则是最小匹配,结束匹配过程
if (matchType == MIN_MATCH_TYPE) {
break;
}
}
} else {
//匹配失败
break;
}
}
//没有匹配结果:匹配字数少于2 或者 匹配没有结束
if (matchFlag < 2 || !flag) {
matchFlag = 0;
}
return matchFlag;
}
}
测试
/**
* @author CC
* @version 1.0
* @since2023/11/7
*/
public class test {
public static void main(String[] args) throws IOException {
SensitiveFilter sensitiveFilter = SensitiveFilter.getInstance();
String txt ="整个机身采用最先进工艺进行制造,是整个东半球最优秀产品,最大程度还原科技震撼!做出最奢侈的产品是终身的信念!";
Set<String> sensitiveWord = sensitiveFilter.getSensitiveWord(txt, SensitiveFilter.MAX_MATCH_TYPE);
System.out.println(sensitiveWord);
}
}
最大匹配规则结果
最小匹配规则结果