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去存储 ...
随机推荐
- 高效的多维空间点索引算法 — Geohash 和 Google S2
原文地址:https://www.jianshu.com/p/7332dcb978b2 引子 每天我们晚上加班回家,可能都会用到滴滴或者共享单车.打开 app 会看到如下的界面: app ...
- QT 出现信号槽不触发的问题
主要有以下三点: 1)槽函数未声明为 slots 类型, 信号函数未声明为 signals所致 2)槽函数和信号函数的参数不一致所致 3)connect关联时失败
- Mybatis--02
主要内容: 1 输入映射和输出映射 输入参数映射 返回值映射 2 动态sql if where foreach sql片段 3 关联查询 一对一关联 一对多关联 4 整合Spring #{}代表一个占 ...
- Linux内存使用调整
前段时间在做播放器的时候,遇到个问题,花了很长时间,做个记录,希望对有需要的人有所帮助: 播放器的播视频的时候,无论是手动切换视频还是到视频播放完成,自动切换视频,一定次数后均出现黑屏现象,偶尔有声音 ...
- Light OJ 1009
题意: 给你一个二分图, (可能不连通) 求可能多的子集元素个数: 思路: 直接DFS 给二分图染色就有了, 统计联通块中个数, 去最大值相加即可. #include<bits/stdc++.h ...
- IDEA中Git更新合并代码后,本地修改丢失
IDEA中,使用Git下载了远程服务器的代码,发现自己修改的代码不在了,此时并没有提交,所以在show history中查看不到,慌死了. 因为有冲突的地方,没有办法合并,所以直接使用了远程的代码 无 ...
- Netty学习4—NIO服务端报错:远程主机强迫关闭了一个现有的连接
1 发现问题 NIO编程中服务端会出现报错 Exception in thread "main" java.io.IOException: 远程主机强迫关闭了一个现有的连接. at ...
- MYSQL连不上
如果你想连接你的MySQL的时候发生这个错误: ERROR 1130: Host '192.168.1.3' is not allowed to connect to this MySQL serve ...
- ios蓝牙详解
最近这段时间在研究蓝牙,也研究了一段时间了现在在下面做个总结 1 其实蓝牙连接只要明白了整体原理,其实挺简单的 2 大部分情况下,手机作为中心管理者,而连接的设备被称为外设,外设的结构有点像一颗大树 ...
- 修改MongoDB密码
修改MongoDB密码 禁用管理员(root)密码 1.找到配置文件mongod.conf,并进入 vim /etc/mongod.conf 2.禁用管理员(root)密码 找到: security: ...