敏感词过滤算法:前缀树算法

背景

平时我们在逛贴吧的时候,我们经常可以看到一些形如 “***”的符号,通过上下文,我们也可以很容易猜到这些词原来是骂人的话,只是被系统和谐了。那么这是如何实现的呢?作为普通人,我们最先想到的一种办法就是把所有敏感串存入一个列表中,然后用户每发一条内容后台就把该内容与敏感串列表的每一项进行匹配,然后把匹配的字符进行和谐。显然这样的效率是很低的。非常影响性能,那么我们有没有其他的算法呢?这就是我这篇博文打算介绍的。

原理讲解

1.首先建立个敏感词前缀树

根节点为空

2.准备好待处理字符串: 哈哈大王八子大猪蹄子哦 ,声明三个指针,分别指向前缀树的根节点以及待处理字符串的开始字符

3.position指向的字符与根节点的所有子节点进行匹配,不匹配,position 和 begin分别指向待处理字符串的下一个字符,tempNode依旧指向 根节点

4.依旧不匹配,position 和begin继续向前走一位,指向“大”,treeNode依旧指向根节点

5.此时 根节点有一个子节点 与 position指向的字符相等,都为‘大’,则tempNode 指向该节点,同时position前进一步,指向‘王’

6.此时把position指向的‘王’ 和 tempNode的所有子节点进行匹配,匹配失败,说明 从begin起头所有串是不存在敏感词的,可以直接输出。此时begin前进一位,position回退到begin的位置,tempNode回退到根节点

7.此时再把position指向的‘王’与tempNode的所有子节点进行匹配,匹配成功,所以tempNode指向该节点,同时position前进一位,指向‘八‘

8.此时再把position指向的‘王’ 与tempNode的所有子节点进行匹配,匹配成功,此时tempNode 指向它的子节点‘八’,同时position前进一位。

9.继续把position指向的字符与tempNode的所有子节点进行匹配,匹配失败。说明以begin起头的不存在非法字符,可以加入到结果集中。 此时begin向前走一位,position回退到begin的位置,同时tempNode回退到根节点。

10.同理,可以发现子‘子‘不匹配,则直接把它加入结果集,同时position 和begin 向前走一位,tempNode指向根节点。

此时position指向 ‘大’,与tempNode的所有 子节点进行匹配,匹配成功,则position和tempNode都走一位,循环执行....

直到position指向‘子’,tempNode指向‘蹄’

11.此时把position与tempNode的所有子节点进行匹配,匹配成功,tempNode指向它的子节点‘子’,此时检查发现tempNode是敏感词树的叶子节点,说明从begin+1开始的位置 到 position这段是敏感词,用和谐词替换掉。替换之后position前进一位,begin跳到position的位置,tempNode回退到根节点

以上,就是全部流程啦,理解了之后看代码就简单多啦

代码讲解

1.前缀树节点结构

private class TreeNode{

//是否最后一个字
private boolean isKeyWordsEnd = false;

//子节点
private Map<Character,TreeNode> subNodes = new HashMap<>();

public void addSubNode(Character key, TreeNode node){
  subNodes.put(key,node);
}

public TreeNode getSubNode(Character key){
  return subNodes.get(key);
}

public boolean isKeyWordsEnd(){
  return isKeyWordsEnd;
}

public void setKeyWordsEnd(Boolean end){
  isKeyWordsEnd = end;
}

2.构建前缀树的方法

public void addSensitiveWord(String words){

  TreeNode tempNode = rootNode;

  for(int i = 0; i < words.length(); i++){

    Character c = words.charAt(i);
    if(!isSymbol(c)){
    continue;
  }

  TreeNode node = tempNode.getSubNode(c);
  if (node == null){
    node = new TreeNode();
    tempNode.addSubNode(c,node);
  }
  // 指针移动
  tempNode = node;

  //如果到了最后一个字符
  if(i == words.length() -1){
    tempNode.setKeyWordsEnd(true);
  }

  }

}
3.算法具体实现

public String filter(String text){

  if (StringUtils.isEmpty(text)){
    return text;
  }

  String sensitiveWords = "***";
  StringBuilder result = new StringBuilder();

  TreeNode 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));
  begin++;
  position = begin;
  tempNode = rootNode;
  continue;
  }else if(tempNode.isKeyWordsEnd()){
    //替换敏感词
    result.append(sensitiveWords);

    position++;
    begin = position;
    tempNode = rootNode;
  }else {
    position++;
  }

}
  result.append(text.substring(begin)); //把剩下的动加入合法集

  return result.toString();
}

小结

最近一直在做项目,所以有一段时间没写文章了,项目也快完成了,就把在项目中使用的一个算法做了下总结,希望能给读者一些帮助。

原文地址:https://www.cnblogs.com/hd-zg/p/10591065.html

时间: 2024-08-30 09:20:53

敏感词过滤算法:前缀树算法的相关文章

浅析敏感词过滤算法(C++)

为了提高查找效率,这里将敏感词用树形结构存储,每个节点有一个map成员,其映射关系为一个string对应一个TreeNode. STL::map是按照operator<比较判断元素是否相同,以及比较元素的大小,然后选择合适的位置插入到树中.为了提高map的插入及查询效率,可以选用hash_map或unordered_map.关于他们的效率,可以参考http://blog.csdn.net/whizchen/article/details/9286557. 下面主要实现了TreeNode类,进行节

[Java Web]敏感词过滤算法

1.DFA算法 DFA算法的原理可以参考这里,简单来说就是通过Map构造出一颗敏感词树,树的每一条由根节点到叶子节点的路径构成一个敏感词,例如下图: 代码简单实现如下: public class TextFilterUtil { //日志 private static final Logger LOG = LoggerFactory.getLogger(TextFilterUtil.class); //敏感词库 private static HashMap sensitiveWordMap =

敏感词过滤的算法原理之DFA算法

参考文档 http://blog.csdn.net/chenssy/article/details/26961957 敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来一看,整个过程如下:读取敏感词库.如果HashSet集合中,获取页面上传文字,然后进行匹配.我就想这个过程肯定是非常慢的.对于他这个没有接触的人来说我想也只能想到这个,更高级点就是正

java实现敏感词过滤(DFA算法)

小Alan在最近的开发中遇到了敏感词过滤,便去网上查阅了很多敏感词过滤的资料,在这里也和大家分享一下自己的理解. 在写之前,小Alan给大家推荐一篇来自http://cmsblogs.com/?p=1031的博文,也会参考部分内容来描述博文. 敏感词过滤应该是不用给大家过多的解释吧?讲白了就是你在项目中输入某些字(比如输入xxoo相关的文字时)时要能检测出来,很多项目中都会有一个敏感词管理模块,在敏感词管理模块中你可以加入敏感词,然后根据加入的敏感词去过滤输入内容中的敏感词并进行相应的处理,要么

转:鏖战双十一-阿里直播平台面临的技术挑战(webSocket, 敏感词过滤等很不错)

转自:http://www.infoq.com/cn/articles/alibaba-broadcast-platform-technology-challenges 鏖战双十一-阿里直播平台面临的技术挑战 作者 陈康贤 发布于 2016年1月28日 | 2 讨论 分享到:微博微信FacebookTwitter有道云笔记邮件分享 稍后阅读 我的阅读清单 前言:一直以来双十一都是以交易为重心,今年当然也是如此,但是这并不妨碍万能的淘宝将双十一打造的让用户更欢乐.体验更丰富.玩法更多样.内容更有趣

转:Java实现敏感词过滤

敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来一看,整个过程如下:读取敏感词库.如果HashSet集合中,获取页面上传文字,然后进行匹配.我就想这个过程肯定是非常慢的.对于他这个没有接触的人来说我想也只能想到这个,更高级点就是正则表达式.但是非常遗憾,这两种方法都是不可行的.当然,在我意识里没有我也没有认知到那个算法可以解决问题,但是Googl

Java实现敏感词过滤

敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来一看,整个过程如下:读取敏感词库.如果HashSet集合中,获取页面上传文字,然后进行匹配.我就想这个过程肯定是非常慢的.对于他这个没有接触的人来说我想也只能想到这个,更高级点就是正则表达式.但是非常遗憾,这两种方法都是不可行的.当然,在我意识里没有我也没有认知到那个算法可以解决问题,但是Googl

Java实现敏感词过滤(转)

敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来一看,整个过程如下:读取敏感词库.如果HashSet集合中,获取页面上传文字,然后进行匹配.我就想这个过程肯定是非常慢的.对于他这个没有接触的人来说我想也只能想到这个,更高级点就是正则表达式.但是非常遗憾,这两种方法都是不可行的.当然,在我意识里没有我也没有认知到那个算法可以解决问题,但是Googl

敏感词过滤

敏感词过滤是很多网站.论坛常用的功能,一下为相关文章: 1.关于java中敏感词检测的一些总结 2.Java 利用DFA算法 屏蔽敏感词 3.Java实现敏感词过滤--DFA算法