一个字符串搜索的Aho-Corasick算法-程序员宅基地

技术标签: c#  python  

Aho和Corasick对KMP算法(Knuth–Morris–Pratt algorithm)进行了改进,Aho-Corasick算法(Aho-Corasick algorithm)利用构建树,总时间复杂度是O(n)。原理图如下(摘自Aho-Corasick string matching in C#):

 

 

 

Building of the keyword tree (figure 1 - after the first step, figure 2 - tree with the fail function)

 

 

 

C#版本的实现代码可以从Aho-Corasick string matching in C#得到,也可以点击这里获得该算法的PDF文档。

这是一个应用示例:

 

预览图

 

它能将载入的RTF文档中的搜索关键字高亮,检索速度较快,示例没有实现全字匹配,算法代码简要如下:

 

 

[c-sharp] view plain copy
 
  1. /* Aho-Corasick text search algorithm implementation 
  2.  *  
  3.  * For more information visit 
  4.  *      - http://www.cs.uku.fi/~kilpelai/BSA05/lectures/slides04.pdf 
  5.  */  
  6. using System;  
  7. using System.Collections;  
  8. namespace EeekSoft.Text  
  9. {  
  10.     /// <summary>  
  11.     /// Interface containing all methods to be implemented  
  12.     /// by string search algorithm  
  13.     /// </summary>  
  14.     public interface IStringSearchAlgorithm  
  15.     {  
  16.         #region Methods & Properties  
  17.         /// <summary>  
  18.         /// Ignore case of letters  
  19.         /// </summary>  
  20.         bool IgnoreCase { getset; }  
  21.         /// <summary>  
  22.         /// List of keywords to search for  
  23.         /// </summary>  
  24.         string[] Keywords { getset; }  
  25.   
  26.         /// <summary>  
  27.         /// Searches passed text and returns all occurrences of any keyword  
  28.         /// </summary>  
  29.         /// <param name="text">Text to search</param>  
  30.         /// <returns>Array of occurrences</returns>  
  31.         StringSearchResult[] FindAll(string text);  
  32.         /// <summary>  
  33.         /// Searches passed text and returns first occurrence of any keyword  
  34.         /// </summary>  
  35.         /// <param name="text">Text to search</param>  
  36.         /// <returns>First occurrence of any keyword (or StringSearchResult.Empty if text doesn't contain any keyword)</returns>  
  37.         StringSearchResult FindFirst(string text);  
  38.         /// <summary>  
  39.         /// Searches passed text and returns true if text contains any keyword  
  40.         /// </summary>  
  41.         /// <param name="text">Text to search</param>  
  42.         /// <returns>True when text contains any keyword</returns>  
  43.         bool ContainsAny(string text);  
  44.         #endregion  
  45.     }  
  46.     /// <summary>  
  47.     /// Structure containing results of search   
  48.     /// (keyword and position in original text)  
  49.     /// </summary>  
  50.     public struct StringSearchResult  
  51.     {  
  52.         #region Members  
  53.         private int _index;  
  54.         private string _keyword;  
  55.         /// <summary>  
  56.         /// Initialize string search result  
  57.         /// </summary>  
  58.         /// <param name="index">Index in text</param>  
  59.         /// <param name="keyword">Found keyword</param>  
  60.         public StringSearchResult(int index, string keyword)  
  61.         {  
  62.             _index = index; _keyword = keyword;  
  63.         }  
  64.   
  65.         /// <summary>  
  66.         /// Returns index of found keyword in original text  
  67.         /// </summary>  
  68.         public int Index  
  69.         {  
  70.             get { return _index; }  
  71.         }  
  72.   
  73.         /// <summary>  
  74.         /// Returns keyword found by this result  
  75.         /// </summary>  
  76.         public string Keyword  
  77.         {  
  78.             get { return _keyword; }  
  79.         }  
  80.   
  81.         /// <summary>  
  82.         /// Returns empty search result  
  83.         /// </summary>  
  84.         public static StringSearchResult Empty  
  85.         {  
  86.             get { return new StringSearchResult(-1, ""); }  
  87.         }  
  88.         #endregion  
  89.     }  
  90.   
  91.     /// <summary>  
  92.     /// Class for searching string for one or multiple   
  93.     /// keywords using efficient Aho-Corasick search algorithm  
  94.     /// </summary>  
  95.     public class StringSearch : IStringSearchAlgorithm  
  96.     {  
  97.         #region Objects  
  98.         /// <summary>  
  99.         /// Tree node representing character and its   
  100.         /// transition and failure function  
  101.         /// </summary>  
  102.         class TreeNode  
  103.         {  
  104.             #region Constructor & Methods  
  105.             /// <summary>  
  106.             /// Initialize tree node with specified character  
  107.             /// </summary>  
  108.             /// <param name="parent">Parent node</param>  
  109.             /// <param name="c">Character</param>  
  110.             public TreeNode(TreeNode parent, char c)  
  111.             {  
  112.                 _char = c; _parent = parent;  
  113.                 _results = new ArrayList();  
  114.                 _resultsAr = new string[] { };  
  115.                 _transitionsAr = new TreeNode[] { };  
  116.                 _transHash = new Hashtable();  
  117.             }  
  118.   
  119.             /// <summary>  
  120.             /// Adds pattern ending in this node  
  121.             /// </summary>  
  122.             /// <param name="result">Pattern</param>  
  123.             public void AddResult(string result)  
  124.             {  
  125.                 if (_results.Contains(result)) return;  
  126.                 _results.Add(result);  
  127.                 _resultsAr = (string[])_results.ToArray(typeof(string));  
  128.             }  
  129.             /// <summary>  
  130.             /// Adds trabsition node  
  131.             /// </summary>  
  132.             /// <param name="node">Node</param>  
  133.             //public void AddTransition(TreeNode node)  
  134.             //{   
  135.             //    AddTransition(node, false);  
  136.             //}  
  137.             /// <summary>  
  138.             /// Adds trabsition node  
  139.             /// </summary>  
  140.             /// <param name="node">Node</param>  
  141.             /// <param name="ignoreCase">Ignore case of letters</param>  
  142.             public void AddTransition(TreeNode node, bool ignoreCase)  
  143.             {  
  144.                 if (ignoreCase) _transHash.Add(char.ToLower(node.Char), node);  
  145.                 else _transHash.Add(node.Char, node);  
  146.                 TreeNode[] ar = new TreeNode[_transHash.Values.Count];  
  147.                 _transHash.Values.CopyTo(ar, 0);  
  148.                 _transitionsAr = ar;  
  149.             }  
  150.             /// <summary>  
  151.             /// Returns transition to specified character (if exists)  
  152.             /// </summary>  
  153.             /// <param name="c">Character</param>  
  154.             /// <param name="ignoreCase">Ignore case of letters</param>  
  155.             /// <returns>Returns TreeNode or null</returns>  
  156.             public TreeNode GetTransition(char c, bool ignoreCase)  
  157.             {  
  158.                 if (ignoreCase)  
  159.                     return (TreeNode)_transHash[char.ToLower(c)];  
  160.                 return (TreeNode)_transHash[c];  
  161.             }  
  162.   
  163.             /// <summary>  
  164.             /// Returns true if node contains transition to specified character  
  165.             /// </summary>  
  166.             /// <param name="c">Character</param>  
  167.             /// <param name="ignoreCase">Ignore case of letters</param>  
  168.             /// <returns>True if transition exists</returns>  
  169.             public bool ContainsTransition(char c, bool ignoreCase)  
  170.             {  
  171.                 return GetTransition(c, ignoreCase) != null;  
  172.             }  
  173.             #endregion  
  174.             #region Properties  
  175.             private char _char;  
  176.             private TreeNode _parent;  
  177.             private TreeNode _failure;  
  178.             private ArrayList _results;  
  179.             private TreeNode[] _transitionsAr;  
  180.             private string[] _resultsAr;  
  181.             private Hashtable _transHash;  
  182.             /// <summary>  
  183.             /// Character  
  184.             /// </summary>  
  185.             public char Char  
  186.             {  
  187.                 get { return _char; }  
  188.             }  
  189.   
  190.             /// <summary>  
  191.             /// Parent tree node  
  192.             /// </summary>  
  193.             public TreeNode Parent  
  194.             {  
  195.                 get { return _parent; }  
  196.             }  
  197.   
  198.             /// <summary>  
  199.             /// Failure function - descendant node  
  200.             /// </summary>  
  201.             public TreeNode Failure  
  202.             {  
  203.                 get { return _failure; }  
  204.                 set { _failure = value; }  
  205.             }  
  206.   
  207.             /// <summary>  
  208.             /// Transition function - list of descendant nodes  
  209.             /// </summary>  
  210.             public TreeNode[] Transitions  
  211.             {  
  212.                 get { return _transitionsAr; }  
  213.             }  
  214.   
  215.             /// <summary>  
  216.             /// Returns list of patterns ending by this letter  
  217.             /// </summary>  
  218.             public string[] Results  
  219.             {  
  220.                 get { return _resultsAr; }  
  221.             }  
  222.             #endregion  
  223.         }  
  224.         #endregion  
  225.         #region Local fields  
  226.         /// <summary>  
  227.         /// Root of keyword tree  
  228.         /// </summary>  
  229.         private TreeNode _root;  
  230.         /// <summary>  
  231.         /// Keywords to search for  
  232.         /// </summary>  
  233.         private string[] _keywords;  
  234.         #endregion  
  235.         #region Initialization  
  236.         /// <summary>  
  237.         /// Initialize search algorithm (Build keyword tree)  
  238.         /// </summary>  
  239.         /// <param name="keywords">Keywords to search for</param>  
  240.         /// <param name="ignoreCase">Ignore case of letters (the default is false)</param>  
  241.         public StringSearch(string[] keywords, bool ignoreCase)  
  242.             : this(keywords)  
  243.         {  
  244.             IgnoreCase = ignoreCase;  
  245.         }  
  246.         /// <summary>  
  247.         /// Initialize search algorithm (Build keyword tree)  
  248.         /// </summary>  
  249.         /// <param name="keywords">Keywords to search for</param>  
  250.         public StringSearch(string[] keywords)  
  251.         {  
  252.             Keywords = keywords;  
  253.         }  
  254.   
  255.         /// <summary>  
  256.         /// Initialize search algorithm with no keywords  
  257.         /// (Use Keywords property)  
  258.         /// </summary>  
  259.         public StringSearch()  
  260.         { }  
  261.         #endregion  
  262.         #region Implementation  
  263.         /// <summary>  
  264.         /// Build tree from specified keywords  
  265.         /// </summary>  
  266.         void BuildTree()  
  267.         {  
  268.             // Build keyword tree and transition function  
  269.             _root = new TreeNode(null' ');  
  270.             foreach (string p in _keywords)  
  271.             {  
  272.                 // add pattern to tree  
  273.                 TreeNode nd = _root;  
  274.                 foreach (char c in p)  
  275.                 {  
  276.                     TreeNode ndNew = null;  
  277.                     foreach (TreeNode trans in nd.Transitions)  
  278.                     {  
  279.                         if (this.IgnoreCase)  
  280.                         {  
  281.                             if (char.ToLower(trans.Char) == char.ToLower(c)) { ndNew = trans; break; }  
  282.                         }  
  283.                         else  
  284.                         {  
  285.                             if (trans.Char == c) { ndNew = trans; break; }  
  286.                         }  
  287.                     }  
  288.                     if (ndNew == null)  
  289.                     {  
  290.                         ndNew = new TreeNode(nd, c);  
  291.                         nd.AddTransition(ndNew, this.IgnoreCase);  
  292.                     }  
  293.                     nd = ndNew;  
  294.                 }  
  295.                 nd.AddResult(p);  
  296.             }  
  297.             // Find failure functions  
  298.             ArrayList nodes = new ArrayList();  
  299.             // level 1 nodes - fail to root node  
  300.             foreach (TreeNode nd in _root.Transitions)  
  301.             {  
  302.                 nd.Failure = _root;  
  303.                 foreach (TreeNode trans in nd.Transitions) nodes.Add(trans);  
  304.             }  
  305.             // other nodes - using BFS  
  306.             while (nodes.Count != 0)  
  307.             {  
  308.                 ArrayList newNodes = new ArrayList();  
  309.                 foreach (TreeNode nd in nodes)  
  310.                 {  
  311.                     TreeNode r = nd.Parent.Failure;  
  312.                     char c = nd.Char;  
  313.                     while (r != null && !r.ContainsTransition(c, this.IgnoreCase)) r = r.Failure;  
  314.                     if (r == null)  
  315.                         nd.Failure = _root;  
  316.                     else  
  317.                     {  
  318.                         nd.Failure = r.GetTransition(c, this.IgnoreCase);  
  319.                         foreach (string result in nd.Failure.Results)  
  320.                             nd.AddResult(result);  
  321.                     }  
  322.                     // add child nodes to BFS list   
  323.                     foreach (TreeNode child in nd.Transitions)  
  324.                         newNodes.Add(child);  
  325.                 }  
  326.                 nodes = newNodes;  
  327.             }  
  328.             _root.Failure = _root;  
  329.         }  
  330.  
  331.         #endregion  
  332.         #region Methods & Properties  
  333.         /// <summary>  
  334.         /// Ignore case of letters  
  335.         /// </summary>  
  336.         public bool IgnoreCase  
  337.         {  
  338.             get;  
  339.             set;  
  340.         }  
  341.         /// <summary>  
  342.         /// Keywords to search for (setting this property is slow, because  
  343.         /// it requieres rebuilding of keyword tree)  
  344.         /// </summary>  
  345.         public string[] Keywords  
  346.         {  
  347.             get { return _keywords; }  
  348.             set  
  349.             {  
  350.                 _keywords = value;  
  351.                 BuildTree();  
  352.             }  
  353.         }  
  354.   
  355.         /// <summary>  
  356.         /// Searches passed text and returns all occurrences of any keyword  
  357.         /// </summary>  
  358.         /// <param name="text">Text to search</param>  
  359.         /// <returns>Array of occurrences</returns>  
  360.         public StringSearchResult[] FindAll(string text)  
  361.         {  
  362.             ArrayList ret = new ArrayList();  
  363.             TreeNode ptr = _root;  
  364.             int index = 0;  
  365.             while (index < text.Length)  
  366.             {  
  367.                 TreeNode trans = null;  
  368.                 while (trans == null)  
  369.                 {  
  370.                     trans = ptr.GetTransition(text[index], this.IgnoreCase);  
  371.                     if (ptr == _root) break;  
  372.                     if (trans == null) ptr = ptr.Failure;  
  373.                 }  
  374.                 if (trans != null) ptr = trans;  
  375.                 foreach (string found in ptr.Results)  
  376.                     ret.Add(new StringSearchResult(index - found.Length + 1, found));  
  377.                 index++;  
  378.             }  
  379.             return (StringSearchResult[])ret.ToArray(typeof(StringSearchResult));  
  380.         }  
  381.   
  382.         /// <summary>  
  383.         /// Searches passed text and returns first occurrence of any keyword  
  384.         /// </summary>  
  385.         /// <param name="text">Text to search</param>  
  386.         /// <returns>First occurrence of any keyword (or StringSearchResult.Empty if text doesn't contain any keyword)</returns>  
  387.         public StringSearchResult FindFirst(string text)  
  388.         {  
  389.             ArrayList ret = new ArrayList();  
  390.             TreeNode ptr = _root;  
  391.             int index = 0;  
  392.             while (index < text.Length)  
  393.             {  
  394.                 TreeNode trans = null;  
  395.                 while (trans == null)  
  396.                 {  
  397.                     trans = ptr.GetTransition(text[index], this.IgnoreCase);  
  398.                     if (ptr == _root) break;  
  399.                     if (trans == null) ptr = ptr.Failure;  
  400.                 }  
  401.                 if (trans != null) ptr = trans;  
  402.                 foreach (string found in ptr.Results)  
  403.                     return new StringSearchResult(index - found.Length + 1, found);  
  404.                 index++;  
  405.             }  
  406.             return StringSearchResult.Empty;  
  407.         }  
  408.   
  409.         /// <summary>  
  410.         /// Searches passed text and returns true if text contains any keyword  
  411.         /// </summary>  
  412.         /// <param name="text">Text to search</param>  
  413.         /// <returns>True when text contains any keyword</returns>  
  414.         public bool ContainsAny(string text)  
  415.         {  
  416.             TreeNode ptr = _root;  
  417.             int index = 0;  
  418.             while (index < text.Length)  
  419.             {  
  420.                 TreeNode trans = null;  
  421.                 while (trans == null)  
  422.                 {  
  423.                     trans = ptr.GetTransition(text[index], this.IgnoreCase);  
  424.                     if (ptr == _root) break;  
  425.                     if (trans == null) ptr = ptr.Failure;  
  426.                 }  
  427.                 if (trans != null) ptr = trans;  
  428.                 if (ptr.Results.Length > 0) return true;  
  429.                 index++;  
  430.             }  
  431.             return false;  
  432.         }  
  433.         #endregion  
  434.     }  
  435. }  

 

 

示例下载页面:http://www.uushare.com/user/m2nlight/file/2722093

转载于:https://www.cnblogs.com/zwb7926/p/3469202.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30651273/article/details/98109617

智能推荐

关于计算机一级考试的相关整理(巨详细版)-程序员宅基地

文章浏览阅读328次,点赞6次,收藏10次。关于计算机一级考试的局详细版整理

Java 面向对象基础篇【接口、抽象类、实现类之间的关系】-程序员宅基地

文章浏览阅读740次,点赞10次,收藏7次。在面向对象设计中,根据具体需求选择使用接口、抽象类或实现类来组织扩展与维护的代码结构 ···

巧用Superset大数据分析平台搞定各类图表_superset分析hive表-程序员宅基地

文章浏览阅读6.2w次,点赞5次,收藏46次。前言其实大数据图表展示的这类平台有很多,Superset是其中之一,最近有个需求对各类图表展示的开发较多,索性将工作量交给这个平台。介绍Superset的中文翻译是快船,而Superset其实是一个自助式数据分析工具,它的主要目标是简化我们的数据探索分析操作,它的强大之处在于整个过程一气呵成,几乎不用片刻的等待。 部署docker方式(推荐)docker pull amancevice/carav_superset分析hive表

win10安全中心误删文件怎么办?解析恢复与预防策略-程序员宅基地

文章浏览阅读1.3k次,点赞28次,收藏21次。在使用Windows 10的过程中,许多用户依赖于其内置的安全中心来保护电脑免受恶意软件的侵害。然而,有时安全中心的误判可能导致重要文件被错误地删除。当面对这种情况时,了解如何恢复误删的文件并掌握预防措施显得尤为重要。本文将为您详细解析恢复误删文件的多种方法,并为您提供一系列实用的预防策略,以确保您的数据安全。

socket PHP:详细简单的socket TCP通信PHP实现_php tcp两个客户端通信-程序员宅基地

文章浏览阅读8.6k次,点赞3次,收藏34次。如果你想直接运行程序实现效果:请直接看 3.3 本地服务器及客服端程序1 背景介绍目标:我希望通过套接字的TCP传输来搭建一个服务器,这个服务器的作用是:接受多个客户端的连接并完成他们的相互通信。比如客户端A,客户端B同时连接到服务器S,客户端A向服务器S发送消息,服务器S会将A的消息转发给B,同理,B的消息也可以通过S被转发到A。这样就实现了客户端A和客户端B之间的相互通信。本次我们只实现..._php tcp两个客户端通信

【数学】简化剩余系、欧拉函数、欧拉定理与扩展欧拉定理-程序员宅基地

文章浏览阅读894次,点赞27次,收藏31次。讲解简化剩余系、欧拉函数、欧拉定理与扩展欧拉定理

随便推点

大数据框架版本_你们公司的大数据框架版本-程序员宅基地

文章浏览阅读157次。Hive 3.12Hadoop 3.1.3hbase 2.0.5spark 3.0.0zookeeper 3.5.7flume 1.9.0ranger 2.0.0sqoop 1.4.7_你们公司的大数据框架版本

jvm学习-程序员宅基地

文章浏览阅读126次。Java虚拟机一 java内存区域和内存溢出异常运行时数据区域栈帧是方法运行期的基础数据结构。程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理线程恢复等基础功能都需要依赖这个计数器来完成。Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为

vue x 兼容iphone_vue 项目对iphoneX底部兼容处理-程序员宅基地

文章浏览阅读379次。import Vue from 'vue'Vue.directive('isIphoneX', {bind: function (el, binding) {const _local = 'ios'let isIphoneX = falseif (_local === 'ios' && window.screen.height) {isIphoneX = window.screen..._min-height: 89vh;

MyBatis-Plus和SpringBoot的整合_<dependency> <groupid>com.baomidou</groupid> <arti-程序员宅基地

文章浏览阅读2.8k次,点赞2次,收藏4次。简介MyBatis-Plus是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。一、MyBatis-Plus和SpringBoot整合应用1.1 项目依赖在原项目依赖上,加上下面依赖<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-start_ com.baomidou mybatis-plus-boot-s

解决cURL resource: Resource id #147; cURL error: SSL certificate problem: unable to get local issuer.._requestcoreexception: curl error: ssl certificate -程序员宅基地

文章浏览阅读3.7k次。我这边抛出这个问题是因为我在php后端接口上 调用了阿里云OSS-SDK:"aliyuncs/oss-sdk-php": "~2.0"请求删除文件的操作后出现这个错误提示的:RequestCoreException: cURL resource: Resource id #147; cURL error: SSL certificate problem: unable to get lo..._requestcoreexception: curl error: ssl certificate problem: unable to get loc

AI绘画工具有哪些?-程序员宅基地

文章浏览阅读1.1k次,点赞40次,收藏6次。NVIDIA GauGAN:NVIDIA GauGAN是一款基于生成对抗网络(GAN)的AI绘画工具,它可以将简单的草图快速转换为逼真的图像,帮助用户实现快速的绘画创作。DeepDream:DeepDream是谷歌开发的一种图像处理算法,它基于卷积神经网络,可以将图像中的模式和特征进行增强和变形,产生具有梦幻般效果的图像。ArtBreeder:ArtBreeder是一个基于神经网络的在线创作平台,它可以通过混合不同图像的特征生成新的艺术作品,帮助用户进行创作和探索。