Aho-Corasick算法实现(简单关键字过滤)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ConsoleAppTest
{
class Program
{
/// <summary>
/// 简单关键字过滤
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
var ss = CheckDirtyWords("sswo1lfsss殺殺殺喫屎阿三大蘇打阿薩大大愛的愛的大量加拉傑拉德拉薩大家安靜杜拉斯的就拉客的就拉省的家裏卡等級了及案例記錄記錄加拉多久啦結束了");
Console.WriteLine(ss);
Console.ReadLine();
} /// <summary>
/// 检查指定的内容是否包含非法关键字
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
protected static bool CheckDirtyWords(string text)
{
var dirtyStr = "wolf|jason|hoho|barry|喫屎";
if (string.IsNullOrEmpty(dirtyStr))
{
return false;
}
List<string> keywords = dirtyStr.Split('|').ToList();
KeywordFilter ks = new KeywordFilter(keywords);
return ks.FindAllKeywords(text).Count > ;
}
} /// <summary>
/// Aho-Corasick算法实现
/// </summary>
public class KeywordFilter
{
/// <summary>
/// 构造节点
/// </summary>
private class Node
{
private Dictionary<char, Node> transDict; public Node(char c, Node parent)
{
this.Char = c;
this.Parent = parent;
this.Transitions = new List<Node>();
this.Results = new List<string>(); this.transDict = new Dictionary<char, Node>();
} public char Char
{
get;
private set;
} public Node Parent
{
get;
private set;
} public Node Failure
{
get;
set;
} public List<Node> Transitions
{
get;
private set;
} public List<string> Results
{
get;
private set;
} public void AddResult(string result)
{
if (!Results.Contains(result))
{
Results.Add(result);
}
} public void AddTransition(Node node)
{
this.transDict.Add(node.Char, node);
this.Transitions = this.transDict.Values.ToList();
} public Node GetTransition(char c)
{
Node node;
if (this.transDict.TryGetValue(c, out node))
{
return node;
} return null;
} public bool ContainsTransition(char c)
{
return GetTransition(c) != null;
}
} private Node root; // 根节点
private string[] keywords; // 所有关键词 public KeywordFilter(IEnumerable<string> keywords)
{
this.keywords = keywords.ToArray();
this.Initialize();
} /// <summary>
/// 根据关键词来初始化所有节点
/// </summary>
private void Initialize()
{
this.root = new Node(' ', null); // 添加模式
foreach (string k in this.keywords)
{
Node n = this.root;
foreach (char c in k)
{
Node temp = null;
foreach (Node tnode in n.Transitions)
{
if (tnode.Char == c)
{
temp = tnode; break;
}
} if (temp == null)
{
temp = new Node(c, n);
n.AddTransition(temp);
}
n = temp;
}
n.AddResult(k);
} // 第一层失败指向根节点
List<Node> nodes = new List<Node>();
foreach (Node node in this.root.Transitions)
{
// 失败指向root
node.Failure = this.root;
foreach (Node trans in node.Transitions)
{
nodes.Add(trans);
}
}
// 其它节点 BFS
while (nodes.Count != )
{
List<Node> newNodes = new List<Node>();
foreach (Node nd in nodes)
{
Node r = nd.Parent.Failure;
char c = nd.Char; while (r != null && !r.ContainsTransition(c))
{
r = r.Failure;
} if (r == null)
{
// 失败指向root
nd.Failure = this.root;
}
else
{
nd.Failure = r.GetTransition(c);
foreach (string result in nd.Failure.Results)
{
nd.AddResult(result);
}
} foreach (Node child in nd.Transitions)
{
newNodes.Add(child);
}
}
nodes = newNodes;
}
// 根节点的失败指向自己
this.root.Failure = this.root;
} /// <summary>
/// 找出所有出现过的关键词
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public List<KeywordSearchResult> FindAllKeywords(string text)
{
List<KeywordSearchResult> list = new List<KeywordSearchResult>(); Node current = this.root;
for (int index = ; index < text.Length; ++index)
{
Node trans;
do
{
trans = current.GetTransition(text[index]); if (current == this.root)
break; if (trans == null)
{
current = current.Failure;
}
} while (trans == null); if (trans != null)
{
current = trans;
} foreach (string s in current.Results)
{
list.Add(new KeywordSearchResult(index - s.Length + , s));
}
} return list;
} /// <summary>
/// 简单地过虑关键词
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public string FilterKeywords(string text)
{
StringBuilder sb = new StringBuilder(); Node current = this.root;
for (int index = ; index < text.Length; index++)
{
Node trans;
do
{
trans = current.GetTransition(text[index]); if (current == this.root)
break; if (trans == null)
{
current = current.Failure;
} } while (trans == null); if (trans != null)
{
current = trans;
} // 处理字符
if (current.Results.Count > )
{
string first = current.Results[];
sb.Remove(sb.Length - first.Length + , first.Length - );// 把匹配到的替换为**
sb.Append(new string('*', current.Results[].Length)); }
else
{
sb.Append(text[index]);
}
} return sb.ToString();
}
} /// <summary>
/// 表示一个查找结果
/// </summary>
public struct KeywordSearchResult
{
private int index;
private string keyword;
public static readonly KeywordSearchResult Empty = new KeywordSearchResult(-, string.Empty); public KeywordSearchResult(int index, string keyword)
{
this.index = index;
this.keyword = keyword;
} /// <summary>
/// 位置
/// </summary>
public int Index
{
get { return index; }
} /// <summary>
/// 关键词
/// </summary>
public string Keyword
{
get { return keyword; }
}
}
}
Aho-Corasick算法实现(简单关键字过滤)的更多相关文章
- 多模字符串匹配算法-Aho–Corasick
背景 在做实际工作中,最简单也最常用的一种自然语言处理方法就是关键词匹配,例如我们要对n条文本进行过滤,那本身是一个过滤词表的,通常进行过滤的代码如下 for (String document : d ...
- Aho - Corasick string matching algorithm
Aho - Corasick string matching algorithm 俗称:多模式匹配算法,它是对 Knuth - Morris - pratt algorithm (单模式匹配算法) 形 ...
- 冒泡排序算法和简单选择排序算法的js实现
之前已经介绍过冒泡排序算法和简单选择排序算法和原理,现在有Js实现. 冒泡排序算法 let dat=[5, 8, 10, 3, 2, 18, 17, 9]; function bubbleSort(d ...
- 短链接及关键字过滤ac自动机设计思路
=============:短链接设计思路:核心:将长字符转为短字符串并建立映射关系,存储redis中.1.使用crc32转换为Long 2.hashids将long encode为最短字符串.作为短 ...
- 机器学习&数据挖掘笔记(常见面试之机器学习算法思想简单梳理)
机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理) 作者:tornadomeet 出处:http://www.cnblogs.com/tornadomeet 前言: 找工作时( ...
- 使用C语言实现二维,三维绘图算法(3)-简单的二维分形
使用C语言实现二维,三维绘图算法(3)-简单的二维分形 ---- 引言---- 每次使用OpenGL或DirectX写三维程序的时候, 都有一种隔靴搔痒的感觉, 对于内部的三维算法的实现不甚了解. 其 ...
- [转]机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理)
机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理) 转自http://www.cnblogs.com/tornadomeet/p/3395593.html 前言: 找工作时(I ...
- 1101: 零起点学算法08——简单的输入和计算(a+b)
1101: 零起点学算法08--简单的输入和计算(a+b) Time Limit: 1 Sec Memory Limit: 128 MB 64bit IO Format: %lldSubmitt ...
- java程序员到底该不该了解一点算法(一个简单的递归计算斐波那契数列的案例说明算法对程序的重要性)
为什么说 “算法是程序的灵魂这句话一点也不为过”,递归计算斐波那契数列的第50项是多少? 方案一:只是单纯的使用递归,递归的那个方法被执行了250多亿次,耗时1分钟还要多. 方案二:用一个map去存储 ...
随机推荐
- for..of和for..in和map、filter等循环区别
1.for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值. for in遍历比较适合遍历对象,不太适合数组,有可能遍历出来的不按照顺序 遍历数组 ,,,,,] for (var ...
- EntityFramework之事务
一.EF事务 引用程序集 using System.Transactions; 用法 var writer = new System.IO.StringWriter(); try { using (v ...
- 专题:CF图论杂题
题目是来自HZW的博客(构造题我是各种不会...) Solved 1 / 1 A CodeForces 500A New Year Transportation Solved 1 / 1 B Code ...
- ES--04
第三十一讲! 分布式文档系统 写一致性原理以及相关参数 课程大纲 (1)consistency,one(primary shard),all(all shard),quorum(default) 我们 ...
- OpenStack实践系列④计算服务Nova
OpenStack实践系列④计算服务Nova 3.6 Nova控制节点的部署创建服务的凭证,完成下列步骤: 创建nova用户,并加入到service项目中,赋予admin权限 [root@node1 ...
- jar运行
#在.bat文件中,输入下面两行代码,双击运行该bat文件即可将带main方法的jar跑起来 title NAME java -jar NAME.jar #当web项目打包成war后,部署到tomca ...
- Golang 优化之路-空结构[转]
写在前面 开发 hashset 常用的套路: map[int]int8 map[int]bool 我们一般只用 map 的键来保存数据,值是没有用的.所以来缓存集合数据会造成内存浪费. 空对象 空对象 ...
- 【原创】大叔经验分享(38)beeline连接hiveserver2报错impersonate
beeline连接hiveserver2报错 Error: Could not open client transport with JDBC Uri: jdbc:hive2://localhost: ...
- mvc 母版页保持不刷新
//比如这是左边菜单栏 <ul class="treeview-menu" id="left_menu"> <li><a href ...
- CSS margin合并
外边距合并 块的顶部外边距和底部外边距有时被组合(折叠)为单个外边距,其大小是组合到其中的最大外边距 发生外边距合并的三种基本情况 1. 相邻的兄弟姐妹元素 <div id="marg ...