【数据结构与算法】DFA算法-关键词匹配-java案例实现

该算法往往是用于匹配一些敏感词、绝对词等,从一篇文章中快速找到其中包含的关键词。

实现思路

        先读取所有关键词并存入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);
    }
}

最大匹配规则结果

最小匹配规则结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值