下发策略,DFA算法优化---敏感词查询

1、定义

有穷自动机FA(Finite Automaton)的每一步操作都是确定的,因此可称为确定型有穷自动机。确定有穷自动机DFA(Deterministic Finite Automaton)就是说当一个状态面对一个输入符号的时候,它所转换到的是一个唯一确定的状态。

2、过程

无意中发现这个算法,发现这个DFA可以很好的解决在限定字段发送,对不规定的词语进行限定的查找,极大的提高效率。

有一段文字,

你好,我是秦始皇的后裔,我有一千多亿的资产被政府冻结了,现在需要诈骗你 100 块钱,用于解冻我们的资产,解冻完成后再骗你一百。

以前我们对一段文字中匹配不规范的词语,往往是采用将敏感词进行一个个的匹配,假设有一个敏感词-诈骗,我们以诈骗为核心,对文字进行匹配,如果存在,则返回错误。

采用DFA算法后,我们以文字为核心,对文字进行拆分,将敏感词运用DFA保存为一个有穷自动机,把拆分的文字进行匹配,极大的提升效率。

        List<String> dirtywords = new ArrayList<>();
        for (String s : dirty) {
            boolean contains = msg.contains(s);
            if (contains) {
                dirtywords.add(s);
            }
        }
        long end = System.currentTimeMillis();
        System.err.println(end - start);
        System.err.println(dirtywords);

 运行结果:2882198个数据

                花费时间为298毫秒

        //进行DFA算法查询
        SensitivewordFilter sensitivewordFilter = new SensitivewordFilter();
        sensitivewordFilter.setDirtyWordLocalCache(dirtyWordLocalCache);

        System.err.println("华丽的分割线------------------------------------");
        start = System.currentTimeMillis();
        Set<String> sensitiveWord = sensitivewordFilter.getSensitiveWord(msg);
        System.err.println(sensitiveWord);
        end = System.currentTimeMillis();
        System.err.println(end - start);

同样的数据,花费为0毫秒,相差巨大

三、下面为DFA算法代码,开箱即用

@Component
public class SensitivewordFilter {

    /**
     * 获取文字中的敏感词
     *
     * @param txt       文字
     * @return Set
     */
    public Set<String> getSensitiveWord(String txt) {
        return getSensitiveWordSets(txt);
    }

    /**
     * 替换敏感字字符
     *
     * @param txt         文本

     * @param replaceChar 替换字符,默认*
     * @return String
     */
    public String replaceSensitiveWord(String txt, String replaceChar) {
        String resultTxt = txt;
        // 获取所有的敏感词
        Set<String> sets = getSensitiveWord(txt);
        for (String str : sets) {
            String replaceString = getReplaceChars(replaceChar, str.length());
            resultTxt = resultTxt.replaceAll(str, replaceString);
        }
        return resultTxt;
    }

    /**
     * 获取替换字符串
     *
     * @param replaceChar 替换符
     * @param length      长度
     * @return String
     */
    private String getReplaceChars(String replaceChar, int length) {
        StringBuilder resultReplace = new StringBuilder(replaceChar);
        for (int i = 1; i < length; i++) {
            resultReplace.append(replaceChar);
        }
        return resultReplace.toString();
    }

    /**
     * 检查文字中是否包含敏感字符,检查规则如下
     * @param txt        文本
     * @return int 如果存在,则返回敏感词字符的长度,不存在返回0
     */
    public int checkSensitiveWord(String txt) {
        Set<String> sets = getSensitiveWordSets(txt);
        return sets.size();
    }

    private Set<String> getSensitiveWordSets(String txt) {
        Set<String> sensitiveWordSets = new HashSet<>();
        for (int n = 0; n < txt.length(); n++) {
            // 判断是否包含敏感字符
            int length = judgeSensitiveWithIndex(txt, n);
            if (length > 0) {
                // 存在,加入list中
                sensitiveWordSets.add(txt.substring(n, n + length));
                // 减1的原因,是因为for会自增
                n = n + length - 1;
            }
        }
        return sensitiveWordSets;
    }

    /**
     * 根据指定位置是否是敏感词的开始
     *
     * @param txt        文本
     * @param beginIndex 开始位置
     * @return int
     */
    private int judgeSensitiveWithIndex(String txt, int beginIndex) {
        // 匹配标识数默认为0
        int matchFlag = 0;
        char word;
        Map nowMap = dirtyWordLocalCache.getSensitiveWordMap();
        for (int i = beginIndex; i < txt.length(); i++) {
            word = txt.charAt(i);
            // 获取指定key
            nowMap = (Map) nowMap.get(word);
            // 存在,则判断是否为最后一个
            if (nowMap != null) {
                // 找到相应key,匹配标识+1
                matchFlag++;
                if ("1".equals(nowMap.get("isEnd"))) {
                    // 如果为最后一个匹配规则,结束循环,返回匹配标识数
                    break;
                }
            } else {
                // 不存在,直接返回
                break;
            }
        }
        // 长度必须大于等于1,为词
        if (matchFlag < 2) {
            matchFlag = 0;
        }
        return matchFlag;
    }



}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值