Community--过滤敏感词

1.前缀树

1.1. 概述

前缀树Trie,又叫字典树,匹配树是一种多路树形结构,是一种用于快速检索的多叉树结构.
Trie的核心思想是空间换时间.利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的.

1.根节点不包含字符,除根节点外的每一个子节点都包含一个字符。
2.从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。
3.每个节点的所有子节点包含的字符互不相同,如果相同要合并。
1.2. 特点

查找效率高,消耗内存大

1.3. 应用

字符串检索,词频统计,字符串排序

1.4. 流程模拟

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.敏感词过滤器

2.1. 自定义敏感词汇库

自行百度
在这里插入图片描述

2.2. 定义前缀树
@Component
public class SensitiveFilter {

  // 前缀树
    private class TrieNode {

        // 关键词结束标识
        private boolean isKeywordEnd = false;

        // 子节点(key是下级字符,value是下级节点)
        private Map<Character, TrieNode> subNodes = new HashMap<>();

        public boolean isKeywordEnd() {
            return isKeywordEnd;
        }

        public void setKeywordEnd(boolean keywordEnd) {
            isKeywordEnd = keywordEnd;
        }

        // 添加子节点
        public void addSubNode(Character c, TrieNode node) {
            subNodes.put(c, node);
        }

        // 获取子节点
        public TrieNode getSubNode(Character c) {
            return subNodes.get(c);
        }

    }

}
2.3. 根据敏感词初始化前缀树
    private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);

    // 替换符
    private static final String REPLACEMENT = "***";

    // 根节点
    private TrieNode rootNode = new TrieNode();

    @PostConstruct
    public void init() {
        try (
                InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
                BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        ) {
            String keyword;
            while ((keyword = reader.readLine()) != null) {
                // 添加到前缀树
                this.addKeyword(keyword);
            }
        } catch (IOException e) {
            logger.error("加载敏感词文件失败: " + e.getMessage());
        }
    }

    // 将一个敏感词添加到前缀树中
    private void addKeyword(String keyword) {
        TrieNode tempNode = rootNode;
        for (int i = 0; i < keyword.length(); i++) {
            char c = keyword.charAt(i);
            TrieNode subNode = tempNode.getSubNode(c);

            if (subNode == null) {
                // 初始化子节点
                subNode = new TrieNode();
                tempNode.addSubNode(c, subNode);
            }

            // 指向子节点,进入下一轮循环
            tempNode = subNode;

            // 设置结束标识
            if (i == keyword.length() - 1) {
                tempNode.setKeywordEnd(true);
            }
        }
    }
2.4. 编写过滤敏感词的方法
 /**
     * 过滤敏感词
     *
     * @param text 待过滤的文本
     * @return 过滤后的文本
     */
    public String filter(String text) {
        if (StringUtils.isBlank(text)) {
            return null;
        }

        // 指针1
        TrieNode tempNode = rootNode;
        // 指针2
        int begin = 0;
        // 指针3
        int position = 0;
        // 结果
        StringBuilder sb = new StringBuilder();

        while (position < text.length()) {
            char c = text.charAt(position);

            // 跳过符号
            if (isSymbol(c)) {
                // 若指针1处于根节点,将此符号计入结果,让指针2向下走一步
                if (tempNode == rootNode) {
                    sb.append(c);
                    begin++;
                }
                // 无论符号在开头或中间,指针3都向下走一步
                position++;
                continue;
            }

            // 检查下级节点
            tempNode = tempNode.getSubNode(c);
            if (tempNode == null) {
                // 以begin开头的字符串不是敏感词
                sb.append(text.charAt(begin));
                // 进入下一个位置
                position = ++begin;
                // 重新指向根节点
                tempNode = rootNode;
            } else if (tempNode.isKeywordEnd()) {
                // 发现敏感词,将begin~position字符串替换掉
                sb.append(REPLACEMENT);
                // 进入下一个位置
                begin = ++position;
                // 重新指向根节点
                tempNode = rootNode;
            } else {
                // 检查下一个字符
                position++;
            }
        }

        // 将最后一批字符计入结果
        sb.append(text.substring(begin));

        return sb.toString();
    }

    // 判断是否为符号
    private boolean isSymbol(Character c) {
        // 0x2E80~0x9FFF 是东亚文字范围
        return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
    }
2.5. 测试
@SpringBootTest
public class SensitiveTests {

    @Autowired
    private SensitiveFilter sensitiveFilter;

    @Test void testSensitiveFilter(){
        String text = "找狼友,到马路上包夜";
        text = sensitiveFilter.filter(text);
        System.out.println(text);

        String text2 = "找★狼★友★,到马路上★包★夜★";
        text2 = sensitiveFilter.filter(text2);
        System.out.println(text2);
    }
}

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
敏感词过滤是指在文本中过滤掉一些敏感词汇,以避免给人带来不必要的困扰或者麻烦。在Java中实现敏感词过滤可以使用正则表达式或者Trie树等算法。这里提供一个简单的Trie树实现敏感词过滤的代码示例: ```java import java.util.HashSet; import java.util.Set; public class SensitiveWordsFilter { private TrieNode root; public SensitiveWordsFilter() { root = new TrieNode(); } public void addWord(String word) { TrieNode node = root; for (char c : word.toCharArray()) { if (!node.containsKey(c)) { node.put(c, new TrieNode()); } node = node.get(c); } node.setEnd(); } public Set<String> filter(String text) { Set<String> set = new HashSet<>(); for (int i = 0; i < text.length(); i++) { TrieNode node = root; for (int j = i; j < text.length(); j++) { char c = text.charAt(j); if (!node.containsKey(c)) { break; } node = node.get(c); if (node.isEnd()) { set.add(text.substring(i, j + 1)); } } } return set; } private static class TrieNode { private TrieNode[] children; private boolean isEnd; public TrieNode() { children = new TrieNode[256]; isEnd = false; } public boolean containsKey(char c) { return children[c] != null; } public void put(char c, TrieNode node) { children[c] = node; } public TrieNode get(char c) { return children[c]; } public void setEnd() { isEnd = true; } public boolean isEnd() { return isEnd; } } } ``` 使用示例: ```java SensitiveWordsFilter filter = new SensitiveWordsFilter(); filter.addWord("敏感词1"); filter.addWord("敏感词2"); Set<String> set = filter.filter("这是一段包含敏感词1和敏感词2的文本。"); System.out.println(set); // 输出 [敏感词1, 敏感词2] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值