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去存储 ...
随机推荐
- Delphi 三层框架 DataSnap 的服务器端设置
elphi 三层框架 DataSnap 的服务器端设置: DataSnap 框架有三个模块:DataSnap Server,Server Module,DataSnap Client Module. ...
- MySQL死锁查询【原创】
死锁详情查询 SELECT SUM(trx_rows_locked) AS rows_locked, SUM(trx_rows_modified) AS rows_modified, SUM(trx_ ...
- 华为QUIDWAY系列路由器的负载均衡配置
作者:邓聪聪 华为系列路由器的负载均衡NQA联动侦测配置案例: 需求:该局域网,IP地址(末位奇数)走联通,IP地址(末位偶数)走电信当某个运营商不可达时,自动切换.通过NQA来确定运营商是否可达., ...
- 设计模式C++学习笔记之十(Builder建造者模式)
建造者模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.一段晦涩难懂的文字,实现创建不同表示的方法就是给创建的过程传入创建的参数.详细的还是看代码吧. 10.1.解释 ...
- cocos开发学习记录
场景的创建和切换 https://blog.csdn.net/lin453701006/article/details/56334578
- hibernate框架学习之二级缓存(测试用例)
HqlDemoApp.java package cn.itcast.h3.query.hql; import java.io.Serializable; import org.hibernate.Qu ...
- 解决mysql 主从数据库同步不一致的方法
接着上文 配置完Mysql 主从之后,在使用中可能会出现主从同步失败的情况. mysql> show slave status\G Slave_IO_Running: Yes Slave_SQL ...
- 【算法】二分查找法&大O表示法
二分查找 基本概念 二分查找是一种算法,其输入是一个有序的元素列表.如果要查找的元素包含在列表中,二分查找返回其位置:否则返回null. 使用二分查找时,每次都排除一半的数字 对于包含n个元素的列表, ...
- 前端----css 选择器
css 为了修饰页面作用, 让页面好看 ⑴ css的引入方式1,行内样式body里面2,内接样式在html里面的 style 里面3,外接样式两种:①链接式: <link rel=" ...
- Python Redis pipeline操作
Redis是建立在TCP协议基础上的CS架构,客户端client对redis server采取请求响应的方式交互. 一般来说客户端从提交请求到得到服务器相应,需要传送两个tcp报文. 设想这样的一个场 ...