SpringBoot_过滤文本敏感词

shangdawei 阅读:56 2022-07-29 11:52:50 评论:0

过滤文本敏感词

针对输入文本,进行敏感词过滤

 

1、实现

2.1 新建一个敏感词文件

sensitive-words.txt

赌博 
嫖娼 
吸毒 
开票 
傻逼

2.2 代码

SensitiveFilter.java

import lombok.Data; 
import org.apache.commons.lang3.CharUtils; 
import org.apache.commons.lang3.StringUtils; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.stereotype.Component; 
 
import javax.annotation.PostConstruct; 
import java.io.BufferedReader; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.util.HashMap; 
import java.util.Map; 
 
@Component 
public class SensitiveFilter { 
 
    private static final Logger LOGGER = LoggerFactory.getLogger(SensitiveFilter.class); 
 
    // 替换符 
    public static final String REPLACEMENT = "***"; 
 
    // 根节点 
    private RootTreeNode rootNode = new RootTreeNode(); 
 
    // @PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次 
    @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); 
            } 
            System.out.println("rootNode = " + rootNode); 
        } catch (Exception e) { 
            LOGGER.error("加载敏感词文件失败" + e.getMessage()); 
        } 
 
    } 
 
    // 将一个敏感词添加到前缀树中 
    private void addKeyword(String keyword) { 
        RootTreeNode tempNode = rootNode; 
        for (int i = 0; i < keyword.length(); i++) { 
            char c = keyword.charAt(i); 
            RootTreeNode subNode = tempNode.getSubNode(c); 
 
            if (subNode == null) { 
                // 初始化子节点 
                subNode = new RootTreeNode(); 
                tempNode.addSubNodes(c, subNode); 
            } 
            // 指向子节点,进入下一轮循环 
            tempNode = subNode; 
 
            //设置结束标识 
            if (i == keyword.length() - 1) { 
                tempNode.setKeywordEnd(true); 
            } 
        } 
    } 
 
    /** 
     * 过滤敏感词 
     * 
     * @param text 待过滤的文本 
     * @return 过滤后的文本 
     */ 
    public String filter(String text) { 
        if (StringUtils.isBlank(text)) { 
            return null; 
        } 
 
        //指针1 
        RootTreeNode 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)); 
                // 进入下一个位置 
                begin++; 
                position = begin; 
                // 指针1 重新指向根节点(重新賦值) 
                tempNode = rootNode; 
            }else if(tempNode.isKeywordEnd()){ 
                // 发现敏感词,将begin~position字符串替换掉 
                sb.append(REPLACEMENT); 
                position++; 
                begin = position; 
                // 指针1 重新指向根节点 
                tempNode = rootNode; 
            }else{ 
                // 检查下一个字符 
                position++; 
            } 
        } 
        //将最后一批字符计入结果 
        sb.append(text.substring(begin)); 
        return sb.toString(); 
    } 
 
    // 判断是否是符号(★ 等特殊符號) 
    private boolean isSymbol(Character c) { 
        //  0x2E80 ~ 0x9FFF 是东亚文字范围 
        return !CharUtils.isAsciiAlphaUpper(c) && (c < 0x2E80 || c > 0x9FFF); 
    } 
 
    // 前缀树 
    @Data 
    private class RootTreeNode { 
        // 描述关键词结束标识 
        private boolean isKeywordEnd = false; 
 
        // 子节点 (key 是下级结点的字符,value是下级节点) 
        private Map<Character, RootTreeNode> subNodes = new HashMap<>(); 
 
        public void addSubNodes(Character c, RootTreeNode node) { 
            subNodes.put(c, node); 
        } 
 
        public RootTreeNode getSubNode(Character c) { 
            return subNodes.get(c); 
        } 
 
    } 
}

2.3 测试

    @Test 
    void test() { 
        System.out.println(sensitiveFilter.filter("这里可以赌博,这里可以嫖娼,这里可以吸毒,哈哈哈")); 
        System.out.println(sensitiveFilter.filter("这里可以|赌|博|,这里可以嫖,娼,这里可以吸~毒,哈哈哈")); 
    }

2.4 结果

这里可以***,这里可以***,这里可以***,哈哈哈 
这里可以|***|,这里可以***,这里可以***,哈哈哈

 


本文参考链接:https://www.cnblogs.com/mmdz/p/15607891.html
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

搜索
排行榜
关注我们

一个IT知识分享的公众号