敏感词过滤

前缀树
• 根节点不包含字符,除根节点外每一个节点都只包含一个字符
• 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串
• 每个节点的所有子节点包含的字符都不相同

前缀树

假设有字符串abcdefghijk,敏感词设置为bc,be,def
思路:
(1)将敏感词建立前缀树,每一个敏感词的最后一个字都做一个标记。如图:
这里写图片描述
(2)有三个变量begin,position,tempNode;
首先,begin指向a,position也指向a,tempNode指向树的根节点root,判断tempNode下是否有a节点,此时tempNode下无a节点,说明a不是敏感词,
begin指向下一位b,position也指向b,此时根节点下有b的节点,那么position指向下一位c,begin不动,tempNode指向b节点,当前节点下有c的节点,并且c有黄色的标志,说明从begin至position位置的字符串(即bc)为敏感词,可以采用替换的方法替换敏感词,也可以直接去除敏感词;
如此反复;

代码实现:

public class SensitiveService{

private class TrieNode{

    //key下一个字符,value是对应的节点
    private Map<Character,TrieNode> subNodes  = new HashMap<Character,TrieNode>();

    //是否是关键词的结尾 true关键词的终结,false继续
    private boolean end = false;
    // 向指定位置添加节点树
    public void addSubNode(Character key, TrieNode trieNode){
        subNodes.put(key,trieNode);
    }
    // 获取下个节点
    public TrieNode getSubNode(Character key){
        return subNodes.get(key);
    }

    public void setKeyWordEnd(boolean end){
        this.end = end;
    }

    public boolean isKeyWordEnd(){
        return this.end;
    }

    public int getSubNodeCount() {
        return subNodes.size();
    }

}

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

/**
 * 判断是否是一个符号
 */
private boolean isSymbol(Character c){
    int ci = (int)c;
    //ox2E80-ox9FFF 东亚文字范围
    return !CharUtils.isAsciiAlphanumeric(c) && (ci < 0x2E80 || ci > 0x9FFF);
}

//建立前缀树,字典树
private  void addWord(String text){
    TrieNode tempNode = rootNode;
    //循环每个字节
    for (int i = 0; i < text.length(); i++){
        Character c = text.charAt(i);

        //过滤空格
        if (isSymbol(c)){
            continue;
        }
        TrieNode node = tempNode.getSubNode(c);
        if (node == null){
            node = new TrieNode();
            tempNode.addSubNode(c,node);
        }
        tempNode = node;
        if(i == text.length() - 1){
            //关键词结束,设置结束标志
            tempNode.setKeyWordEnd(true);
        }
    }
}

//过滤敏感词
public String filter(String text){
    if(StringUtils.isBlank(text)){
        return text;
    }
    StringBuilder result = new StringBuilder();
    String replaceWord = "***";  //替代的字符
    TrieNode tempNode = rootNode;
    int begin = 0;  //开始位置
    int position = 0;  //当前比较的位置

    while(position < text.length()){
        Character c = text.charAt(position);
        //空格直接跳过
        if(isSymbol(c)){
            if(tempNode == rootNode){
                result.append(c);
                ++begin;
            }
            ++position;
            continue;
        }
        tempNode = tempNode.getSubNode(c);
        //当前位置的匹配结束
        if(tempNode == null){
            // 以begin开始的字符串不存在敏感词
            result.append(text.charAt(begin));
            // 跳到下一个字符开始测试
            position = begin + 1;
            begin = position;
            //回到树的初始节点
            tempNode = rootNode;
        }else if(tempNode.isKeyWordEnd()){
            // 发现敏感词, 从begin到position的位置用replacement替换掉
            result.append(replaceWord);
            position = position + 1;
            begin = position;
            tempNode = rootNode;
        }else{
            ++position;
        }
    }
    result.append(text.substring(begin));
    return result.toString();
}



public static  void main(String[] args){
    SensitiveService sensitiveService = new SensitiveService();
    sensitiveService.addWord("色情");
    sensitiveService.addWord("赌博");
    String str = "你好 ▄色▄▄情▄";
    System.out.println(sensitiveService.filter(str));
}

}
“`

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值