敏感词过滤一

发布于:2025-08-11 ⋅ 阅读:(17) ⋅ 点赞:(0)

实现了一个基于前缀树(Trie 树)的敏感词过滤工具类SimpleTrie,用于高效地检测文本中是否包含敏感词。下面我将对这个类进行解析,并说明其使用方法和特点。

核心功能解析

  1. 前缀树结构

    • 使用Map<Character, Object>作为节点,每个节点存储字符到子节点的映射
    • 特殊字符CHARACTER_END = '\0'标记一个敏感词的结束
  2. 构造方法

    • 接收敏感词集合,构建前缀树
    • 对敏感词进行排序,优先处理较短的敏感词
    • 构建树时,如果遇到已标记结束的节点则停止,实现最短匹配原则
  3. 主要方法

    • isValid(String text):检查文本是否合法(不包含任何敏感词)
    • validate(String text):获取文本中包含的所有敏感词(去重)
  4. 递归辅助方法

    • recursion():用于验证文本是否包含敏感词
    • recursionWithResult():在验证的同时记录匹配到的敏感词
import cn.hutool.core.collection.CollUtil;

import java.util.*;

/**
 * 基于前缀树,实现敏感词的校验
 * <p>
 * 相比 Apache Common 提供的 PatriciaTrie 来说,性能可能会更加好一些。
 *
 */
@SuppressWarnings("unchecked")
public class SimpleTrie {

    /**
     * 一个敏感词结束后对应的 key
     */
    private static final Character CHARACTER_END = '\0';

    /**
     * 使用敏感词,构建的前缀树
     */
    private final Map<Character, Object> children;

    /**
     * 基于字符串,构建前缀树
     *
     * @param strs 字符串数组
     */
    public SimpleTrie(Collection<String> strs) {
        // 排序,优先使用较短的前缀
        strs = CollUtil.sort(strs, String::compareTo);
        // 构建树
        children = new HashMap<>();
        for (String str : strs) {
            Map<Character, Object> child = children;
            // 遍历每个字符
            for (Character c : str.toCharArray()) {
                // 如果已经到达结束,就没必要在添加更长的敏感词。
                // 例如说,有两个敏感词是:吃饭啊、吃饭。输入一句话是 “我要吃饭啊”,则只要匹配到 “吃饭” 这个敏感词即可。
                if (child.containsKey(CHARACTER_END)) {
                    break;
                }
                if (!child.containsKey(c)) {
                    child.put(c, new HashMap<>());
                }
                child = (Map<Character, Object>) child.get(c);
            }
            // 结束
            child.put(CHARACTER_END, null);
        }
    }

    /**
     * 验证文本是否合法,即不包含敏感词
     *
     * @param text 文本
     * @return 是否 true-合法 false-不合法
     */
    public boolean isValid(String text) {
        // 遍历 text,使用每一个 [i, n) 段的字符串,使用 children 前缀树匹配,是否包含敏感词
        for (int i = 0; i < text.length(); i++) {
            Map<Character, Object> child = (Map<Character, Object>) children.get(text.charAt(i));
            if (child == null) {
                continue;
            }
            boolean ok = recursion(text, i + 1, child);
            if (!ok) {
                return false;
            }
        }
        return true;
    }

    /**
     * 验证文本从指定位置开始,是否不包含某个敏感词
     *
     * @param text  文本
   

网站公告

今日签到

点亮在社区的每一天
去签到