首页 > 编程语言 >Aho-Corasick 算法 AC自动机实现

Aho-Corasick 算法 AC自动机实现

时间:2023-09-22 17:45:42浏览次数:47  
标签:AC 自动机 结点 list Aho she Corasick 失配

敏感词过滤在社区发帖、网站检索、短信发送等场景下是很常见的需求,尤其是在高并发场景下如何实现敏感词过滤,都对过滤算法提出了更高的性能要求,Ahocorasick算法能够实现毫秒级的万字过滤匹配,能够很好的满足各种场景下的敏感词过滤需求。

Aho-Corasick算法通过将模式串预处理为确定有限状态自动机,对待匹配文本扫描一遍就能完成匹配。算法复杂度为O(n),即与模式串的数量和长度无关。AC自动机是多模式匹配的一个经典数据结构,原理是和KMP一样的构造Fail指针,不过AC自动机是在Trie树上构造的,但原理是一样的。

多模式匹配:
多模式匹配就是有多个模式串P1,P2,P3…,Pm,求出所有这些模式串在连续文本T1…n中的所有可能出现的位置。

例如:求出模式集合 {“nihao”,“hao”,“hs”,“hsr”} 在给定文本 sdmfhsgnshejfgnihaofhsrnihao 中所有可能出现的位置。

想要了解Aho-Corasick算法,就首先要从字典树与DFA开始说起:

字典树(Trie)

https://www.cnblogs.com/vipsoft/p/17722820.html

字典树(Trie)是一种很特别的树状信息检索数据结构。利用字符串的公共前缀(common-prefix)来减少查询时间,搜索时间为O(d),d为树的深度。
字典树的原则:

  • 根节点不含字符
  • 根节点到某一终点连起来即为搜索字符串
  • 任意节点的所有子节点包含字符不同
    image

AC 算法思想

AC算法的主要思想就是构造的有限状态自动机,根据有限状态自动机会根据输入进行模式串匹配。有限状态自动机会随着字符的输入而发生状态转移,转移的状态有如下三种:

  • success 状态,即AC自动机根据输入有能直接到达的状态;
  • failure 状态,即AC自动机根据输入没有直接到达的状态,这时候就会发生跳转,跳转到其他一个路径;
  • output 状态,即成功匹配到一个输入段;

示例讲解
以经典的ushers为例,模式串是he/ she/ his /hers 构建字典树,如图:(红色表示接受态)
image

文本为ushers , 构建的自动机如图(带虚线)
自动机从根节点0出发,首先尝试按success表转移
按照文本的指示转移,也就是接收一个u, 此时success表中并没有相应路线,转移失败,失败了则按照failure表回去。
按照文本指示,这次接收一个s,转移到状态3,成功了继续按success表转移,h到状态4,e到状态5
r失败由5跳转步骤2,或者遇到output表中标明的“可输出状态”(she)。此时输出匹配到的模式串,然后将此状态视作普通的状态继续转移。

算法高效之处在于,当自动机接受了“ushe”之后,再接受一个r会导致无法按照success表转移,此时自动机会聪明地按照failure表转移到2号状态,并经过几次转移后输出“hers”。来到2号状态的路不止一条,从根节点一路往下,“h→e”也可以到达。而这个“he”恰好是“ushe”的结尾,状态机就仿佛是压根就没失败过,也没有接受过中间的字符“us”,直接就从初始状态按照“he”的路径走过来一样。

功能解析

用 5 个模式串:"she","he","say","shr","her" 所建的字典树
image
通过分析可知,"she" 具有后缀字符串 "he","her" 具有前缀字符串,因此当 "she" 模式串发生失配的时候,就可以通过失配指针继续匹配 "her" 模式串,那么就需要将 "she" 中的 "h" 结点的失配指针指向 "her" 的 "h" 结点,将 "she" 中的 "e" 结点的失配指针指向 "her" 的 "e" 结点。至于其他的结点,由于不存在共有的前缀字符串和后缀字符串,因此它们的失配指针指向根结点。因此对于如图字典树,失配指针的关系如图所示:
image
通过分析可以得知,进行跳转的另一个模式串的结点深度一定小于跳转之前的结点的深度,这是因为若跳转后的结点深度大于原结点的深度,就无法保证跳转后模式串的前缀字符串与进行跳转的模式串的后缀字符串相匹配,这样结点数量完全不够。
例如上文的例子中,通过失配指针联系的 "she" 中的 "h" 结点和 "her" 的 "h" 结点(蓝色标出)中前者的层数大于后者, "she" 中的 "e" 结点和 "her" 的 "e" 结点(紫色标出)中前者的层数也大于后者:
image
根据这个特点,我们可以通过访问当前结点的双亲结点的方式进行试探,对于某一个字母结点(原字母),通过对其双亲的失配指针的访问,寻找到其他的结点,这个结点满足其孩子结点中存在与原字母相同的结点,此时就把原字母结点的失配指针指向寻找到的结点中与原字母相同的孩子结点。若访问到了根结点,没有发现符合要求的结点,则失配指针指向根结点。
image

代码示例(Python)

ahocorasick 目前改名为 pyahocorasick
https://pypi.tuna.tsinghua.edu.cn/simple/pyahocorasick/

#安装 ahocorasick 库
pip install pyahocorasick==1.4.4 -i https://pypi.tuna.tsinghua.edu.cn/simple
# coding:utf-8
import ahocorasick


def make_AC(AC, word_set):
    for word in word_set:
        AC.add_word(word, word)
    return AC


def test_ahocorasick():
    '''
    ahocosick:自动机的意思
    可实现自动批量匹配字符串的作用,即可一次返回该条字符串中命中的所有关键词
    '''
    key_list = ["苹果", "香蕉", "梨", "橙子", "柚子", "火龙果", "柿子", "猕猴挑"]
    AC_KEY = ahocorasick.Automaton()
    AC_KEY = make_AC(AC_KEY, set(key_list))
    AC_KEY.make_automaton()
    test_str_list = ["我最喜欢吃的水果有:苹果、柚子和香蕉", "我也喜欢吃香蕉,但是我不喜欢吃梨"]
    for content in test_str_list:
        name_list = set()
        for item in AC_KEY.iter(content):  # 将AC_KEY中的每一项与content内容作对比,若匹配则返回
            name_list.add(item[1])
        name_list = list(name_list)
        if len(name_list) > 0:
            print("\n", content, "--->命中的关键词有:", "、".join(name_list))


if __name__ == "__main__":
    test_ahocorasick()

参考: https://www.cnblogs.com/linfangnan/p/12651873.html https://www.cnblogs.com/cmmdc/p/7337611.html

标签:AC,自动机,结点,list,Aho,she,Corasick,失配
From: https://www.cnblogs.com/vipsoft/p/17722761.html

相关文章

  • ClassNotfoundException:java.net.InetAddress$CacheEntry
    一个需求,需要修改本地的dns解析,去验证业务的正确性,修改本地的hosts文件需要频繁的修改本地磁盘文件。使用工具包(https://github.com/tanhaichao/javahost)这个工具类实际是通过反射机制,去修改了InetAddress中的cache值,来实现dns解析的修改。CloseableHttpClient方法在做connect的......
  • AppCode 2023:智能IDE助力iOS/macOS开发
    AppCode2023是一款专为iOS和macOS开发人员打造的智能集成开发环境(IDE)。它提供了强大的代码编辑、调试、测试和版本控制功能,帮助开发者高效地创建出色的iOS和macOS应用程序。→→↓↓载AppCode2023AppCode2023的智能代码编辑器支持自动完成、代码提示、代码重构和错误检查等......
  • 2023.9.22 AT practise
    ARC083F显然每个小球必须被\((0,y)\)或\((x,0)\)中的一个收掉,那么把\(i\)的球看成一条边,链接两个机器人。因为\(2n\)个小球对应\(2n\)条边,故建图出来是一个基环树森林。考虑把每条边定向,对应的就是那个球被那个机器人收了。那么每个基环树只有两种情况(环的方向)。现......
  • [IJCAI 2023]Preventing Attacks in Interbank Credit Rating with Selective-aware G
    [IJCAI2023]PreventingAttacksinInterbankCreditRatingwithSelective-awareGraphNeuralNetwork问题文章研究的是对银行间信用评价的攻击的预防。点是银行,边是银行间的借贷关系。攻击方式有特征攻击(改特征)和结构攻击(加边),目标是点预测。模型选择表示层通过伯努利......
  • 缓存Cache
    研究生课程老师给了一篇论文,是关于缓存的,看完Abstract一脸懵逼之后决定来恶补一下,视频是观看的计算机组成原理(哈工大刘宏伟),这个随笔里的截图什么也都是视频里直接截图的,我只是想做个笔记自己之后再看~~~。一、缓存存在的目的程序局部性原理:通俗来讲就是一个变量在程序运行过程......
  • Apache Log4j Server CVE-2017-5645 反序列化命令执行漏洞
    漏洞描述攻击者可以通过发送一个特别制作的2进制payload,在组件将字节反序列化为对象时,触发并执行构造的payload代码。该漏洞主要是由于在处理ObjectInputStream时,接收函数对于不可靠来源的input没有过滤。可以通过给TcpSocketServer和UdpSocketServer添加可配置的过滤功能以及一......
  • 》》》oracle中用row_number查询最早一条数据
    转载:SQL中row_number() over(partition by)的用法说明_Mysql_脚本之家(jb51.net)select*from{selectcj.xh,--学生学号cj.cj,--学生成绩cj.ks_sj,--考试时间row_number()over(partitionbycj.xhorderbycj.ks_sjdesc)numfromks_cjcj--考......
  • WPF 中使用 Pack URI
    在标记中使用PackURI在标记中,使用packURI设置某个属性的元素,从而指定packURI。例如:<elementattribute="pack://application:,,,/File.xaml"/>表1阐释了可以在标记中指定的各种绝对packURI。表1:标记中的绝对PackURI文件绝对packURI资源文件-本......
  • 手动下载并安装 PHP 和 WinCache
    https://learn.microsoft.com/zh-cn/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php手动下载并安装PHP和WinCache打开浏览器到 WindowsforPHP下载页 并下载PHP非线程安全zip包。从 适用于PHP的......
  • 【UVA 11175】From D to E and Back 题解(图论)
    取具有n个顶点和m条边的任意有向图D。你可以在以下方式。E将有m个顶点,每个顶点对应于D的每条边。例如,如果D有一条边uv,那么E将有一个叫做uv的顶点。现在,每当D有边uv和vw时,E就会有边顶点uv到顶点vw。E中没有其他边。你将得到一张E图,并且必须确定E是否有可能是某些有向图D的图的卧......