通过DFA算法实现大文本敏感词过滤

敏感词过滤就是把文本中的违规词汇替换成“*”或者直接过滤。实际上有很多种实现方法

1.字符串匹配

通过Java的contains进行字符串匹配。使用这种的好处就是实现起来方便,但缺点就是文本和敏感词汇量大的时候它的效率是非常低的,并且是无法告诉我们具体的敏感词和下标。它只适合用于小规模文本或词汇量小的场景下

public static boolean containsSensitiveWord(String text) {
        ReadTxtFiles readTxtFiles = new ReadTxtFiles();
        //获取敏感词文本词
        List<String> sensitiveWords = readTxtFiles.readTxtFiles(DAFFilter.class.getClassLoader().getResource("lexfiles").getFile());
        //进行循环判断
        for (String sensitiveWord : sensitiveWords) {
            if (text.contains(sensitiveWord)) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        String text = "张三是个大xx";
        if (containsSensitiveWord(text)) {
            System.out.println("文本中存在敏感词");
        } else {
            System.out.println("文本中不存在敏感词");
        }
    }

2.前缀树

以下博主说的比较详细,就不过多阐述

经典数据结构——前缀树

3.DFA算法

DFA(Deterministic Finite Automaton,确定有限状态自动机)是一种用于字符串匹配和文本搜索的经典算法。特别适用于敏感词过滤

首先,为每个敏感词构建DFA。这个过程从一个初始状态开始,对于敏感词中的每个字符,如果当前状态下没有对应该字符的转换,则创建一个新的状态,并添加一条从当前状态到新状态的转换,这条转换由该字符触发。如果已经有了对应该字符的转换,则沿着这条转换到达下一个状态。重复这个过程直到敏感词的每个字符都被处理。最后一个字符对应的状态被标记为接受状态,意味着到达这个状态表示找到了一个敏感词。

假设我们的敏感词汇包含"abc","abd"。首先将这两个字符串构建不同的DFA:

  • 初始状态0,对于输入c转到状态1,对于输入b转到状态4。
  • 状态1,对于输入a转到状态2。
  • 状态2,对于输入t转到状态3,状态3是接受状态,意味着找到了敏感词cat。
  • 同理,状态4对于输入a转到状态5,状态5对于输入t转到状态6,状态6是接受状态,意味着找到了敏感词bat。

过滤文本:

当需要检测一段文本时,从DFA的初始状态和文本的第一个字符开始。对于文本中的每个字符,根据当前状态和字符确定下一个状态。如果存在对应字符的转换,则跟随这条转换到达下一个状态;如果不存在,则返回到初始状态。如果在某个点达到了接受状态,意味着匹配到了一个敏感词。然后可以选择标记或替换该敏感词,并继续处理文本的剩余部分。

现在,如果我们需要过滤一段文本:“我有一只狗叫:abc”,我们从初始状态0开始,遇到c转到状态1,接着a转到状态2,然后t转到状态3,此时达到接受状态,意味着我们发现了敏感词cat。根据需要,可以对这个敏感词进行标记或替换,然后继续处理文本的剩余部分。

public class DAFFilter {

    // 构建敏感词的DFA
    private Set<String> sensitiveWords;
    private Map<Character, Object> dfa;

    public DAFFilter(Set<String> sensitiveWords) {
        this.sensitiveWords = sensitiveWords;
        buildDFA();
    }

    // 构建DFA
    private void buildDFA() {
        dfa = new HashMap<>();
        for (String word : sensitiveWords) {
            Map<Character, Object> current = dfa;
            for (int i = 0; i < word.length(); i++) {
                char c = word.charAt(i);
                if (!current.containsKey(c)) {
                    current.put(c, new HashMap<Character, Object>());
                }
                if (i == word.length() - 1) {
                    ((Map<Character, Object>) current.get(c)).put('!', '!'); // 使用一个特殊的字符表示敏感词的结尾
                } else {
                    current = (Map<Character, Object>) current.get(c);
                }
            }
        }
    }

    // 过滤敏感词
    public String filter(String text) {
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            Map<Character, Object> current = dfa;
            int j = i;
            while (current.containsKey(c)) {
                if (((Map<Character, Object>) current.get(c)).containsKey('!')) {
                    for (int k = i; k <= j; k++) {
                        result.append("*"); // 将敏感词替换为*
                    }
                    i = j; // 更新i
                    break;
                } else {
                    if (j == text.length() - 1) {
                        break;
                    }
                    current = (Map<Character, Object>) current.get(c);
                    c = text.charAt(++j);
                }
            }
            result.append(text.charAt(i)); // 添加未被替换的字符
        }
        return result.toString();
    }

    public static void main(String[] args) {
        ReadTxtFiles readTxtFiles = new ReadTxtFiles();
        //获取敏感词词
        Set<String> sensitiveWords =readTxtFiles.readTxtFiles(DAFFilter.class.getClassLoader().getResource("lexfiles").getFile()).stream().collect(Collectors.toSet());
        DAFFilter dafFilter = new DAFFilter(sensitiveWords);
        System.out.println(dafFilter.filter("张三是个大傻比"));
    }
}

运行结果:

敏感词汇:

以上只是实现简单的敏感词过滤功能,如果需要可以扩展

推荐基于DFA算法实现的高性能Java敏感词过滤工具

GitHub - houbb/sensitive-word: 👮‍♂️The sensitive word tool for java.(敏感词/违禁词/违法词/脏词。基于 DFA 算法实现的高性能 java 敏感词过滤工具框架。请勿发布涉及政治、广告、营销、翻墙、违反国家法律法规等内容。高性能敏感词检测过滤组件,附带繁体简体互换,支持全角半角互换,汉字转拼音,模糊搜索等功能。)

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值