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去存储 ...
随机推荐
- 词向量之Word2vector原理浅析
原文地址:https://www.jianshu.com/p/b2da4d94a122 一.概述 本文主要是从deep learning for nlp课程的讲义中学习.总结google word2v ...
- ffmpeg 版本升级到 4.0 增加 libaom 库 [AOMedia 的 AV1 视频编码格式]
win10 中交叉编译 libaom 时 注意事项 libaom 源代码 下载 git -c "http.proxy=ip:port" clone https://aomedia. ...
- 004_为什么不推荐APP使用SSL-PINNING
背景 之前工作的经历,前面技术团队的APP使用了SSL-PINNING,服务器SSL证书到期前,测试环境更换证书,在更换配置OK后,发现APP停止服务了.所有的请求全部都失败. 后来查到是APP使用了 ...
- unit test
1) State vs Behaviour Verificationhttps://manas.tech/blog/2009/04/30/state-vs-behaviour-verification ...
- Light OJ 1102
题意: 给你一个数 N , 求分成 K 个数 (可以为 0 ) 的种数: 思路: 类似 在K个抽屉放入 N 个苹果, 不为0, 就是 在 n-1 个空隙中选 m-1个: 为 0, 就可以先在 K 个抽 ...
- bzoj3730 震波 [动态点分治,树状数组]
传送门 思路 如果没有强制在线的话可以离线之后CDQ分治随便搞. 有了强制在线之后--可能可以二维线段树?然而我不会算空间. 然后我们莫名其妙地想到了动态点分治,然后这题就差不多做完了. 点分树有一个 ...
- 在线HTTP POST/GET接口测试工具 - aTool在线工具
百度搜索标题或直接访问网址如下 网址:http://www.atool.org/httptest.php 很好用的在线http get/post 测试工具
- 树·二叉查找树ADT(二叉搜索树/排序树)
1.定义 对于每个节点X,它的左子树中所有的项的值小于X的值,右子树所有项的值大于X的值. 如图:任意一个节点,都满足定义,其左子树的所有值小于它,右子树的所有值大于它. 2.平均深度 在大O模型中, ...
- java+appium 自动化环境搭建
1.安装JDK1.7及以上 2.下载解压sdk并且配置环境变量: ANDROID_HOME:...\adt-bundle-windows-x86_64-20140702\sdk PATH:%ANDRO ...
- Confluence 6 虚拟文件和文件夹
在取消点赞事件中,你可能会遇到 WebDAV 客户端的问题或者不稳定的情况,你可以启用访问自动创建(虚拟)文件和文件夹. 备注: 在默认情况下,这个选项隐藏在 'WebDAV Configurati ...