Java实现DFA算法敏感词过滤

本文介绍了如何使用Java实现DFA算法来过滤文本中的敏感词,通过MySQL数据库存储敏感词,并演示了如何模拟用户输入进行动态替换。关键部分包括敏感词树结构构建和实际代码实现。

Java实现DFA算法敏感词过滤。

一. 应用场景

模拟非法词汇自动替换成*字符,且敏感词汇支持动态调整。

效果如下,若配置了敏感词:今天,则当用户在输入:今天,天气真不错。实际应该输出:**,天气真不错

二. 实现思路

  • 使用MySQL作为敏感词库
  • 使用DFA算法实现文字过滤

Q:什么是DFA?

DFA全称为:Deterministic Finite Automaton,即确定有穷自动机。其特征为:有一个有限状态集合和一些从一个状态通向另一个状态的边,每条边上标记有一个符号,其中一个状态是初态,某些状态是终态。但不同于不确定的有限自动机,DFA中不会有从同一状态出发的两条边标志有相同的符号。
确定:状态以及引起状态转换的事件都是可确定的,不存在“意外”。
有穷:状态以及事件的数量都是可穷举的。

DFA算法模型如下:

state_event_dict = {
   
   
    "匹": {
   
   
        "配": {
   
   
            "算": {
   
   
                "法": {
   
   
                    "is_end": True
                },
                "is_end": False
            },
            "关": {
   
   
                "键": {
   
   
                    "词": {
   
   
                        "is_end": True
                    },
                    "is_end": False
                },
                "is_end": False
            },
            "is_end": False
        },
        "is_end": False
    },
    "信": {
   
   
        "息": {
   
   
            "抽": {
   
   
                "取": {
   
   
                    "is_end": True
                },
                "is_end": False
            },
            "is_end": False
        },
        "is_end": False
    }
}

用通俗易懂的话来解释,就是将数据库中的敏感词进行建立树结构,举个例子,数据库的敏感词汇有三个,分别是:今天,今天很好,今天真烦。

建立树结构,并且标记好三个词汇的非叶子节点和叶子节点(即最后一个字符是叶子节点),并且制定好匹配规则,只有碰到叶子节点才算一次过滤:

image-20220302161408777

模拟用户输入以下一句话:

我觉得今天还行。

接下来我们将这句话逐个字拆分并将每一个字代入到上面的树状结构图中。

前面三个字不在敏感词树中直接可以跳过,直到遇到了这个字,发现匹配上了敏感词树,接下来看树状结构发现只有下一个字是才能被捕获,继续往下走果然发现这个字也匹配到了;

再接着走发现在树结构中这个字的下一个字只有匹配到或者才能继续匹配,而用户输入的下一个字是,第一步判断当前已经走到了叶子节点,故先将今天置为敏感词,然后将这个字从Top顶节点中重新继续流转,发现无法匹配。

过滤结束,且当前的节点是叶子节点,故这句话仅仅被敏感词过滤了今天这两个字,最终的过滤结果应该是:

我觉得**还行

要注意的是只有完整的碰到过一次叶子节点才算一次过滤,且一句话可以被多次过滤。以上就是针对DFA算法的简单说明。

三. 源码实现

理论知识加身,接下来就该实干了。Talk is cheap, show me the code:

import java.util.HashMap;
import java.util.Map;

/**
 * @author: Vainycos
 * @description 敏感字树生成器
 * @date: 2021/12/4 12:45
 */
public class TreeGenerator {
   
   

    /**
     * 将指定的词分成字构建到一棵树中。
     *
     * @param tree
     *            字树
     * @param sensitiveWord
     *            敏感词词
     * @return
     */
    public static void addWord2Tree(Map<String, Map> tree, String sensitiveWord) {
   
   
        addWord2Tree(tree, sensitiveWord, 0);
    }

    private static Map<String, Map> addWord2Tree(Map<String, Map> tree,
                                                 String word, int index) {
   
   
        if (index == word.length()) {
   
   
            tree.put(Finder.TREE_END_KEY, generateWordMap(word));
            return tree;
        }
        String next = word.substring(index, index + 1);
        Map<String, Map> subTree = tree.get(next);
        if (subTree == null) {
   
   
            subTree = new HashMap<String, Map>();
        }
        tree.put(next, addWord2Tree(subTree, word, index + 1));
        return tree;
    }

    private static Map<String, Object> generateWordMap(String word) {
   
   
        Map<String, Object> wordMap = new HashMap<String, Object>();
        wordMap.put(Finder.WORD_VALUE, word);
        wordMap.put(Finder.WORD_LENGTH, word.length());
        return wordMap;
    }
}
public class TextAnalysis {
   
   

	/**
	 * 
	 * 分析文本,返回搜寻到的所有敏感字
	 * 
	 * @author hymer
	 * @param tree
	 *            敏感字树
	 * @param text
	 *            待分析的文本
	 * @return
	 */
	public Set<String> analysis(Map<String, Map> tree, String text) {
   
   
		Set<String> words = new LinkedHashSet<String>();
		if (text != null && text.trim().length() > 0) {
   
   
			analysis(tree, text, words);
		}
		return words;
	}

	/**
	 * 替换文本中的敏感词
	 * 
	 * @param tree
	
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值