多模字符串匹配算法原理及Java实现代码

  

多模字符串匹配算法在这里指的是在一个字符串中寻找多个模式字符字串的问题。一般来说,给出一个长字符串和很多短模式字符串,如何最快最省的求出哪些模式字符串出现在长字符串中是我们所要思考的。该算法广泛应用于关键字过滤,入侵检测,病毒检测,分词等等问题中。多模问题一般有Trie树,AC算法,WM算法等等。

  


  

  

在做实际工作中,最简单也最常用的一种自然语言处理方法就是关键词匹配,例如我们要对n条文本进行过滤,那本身是一个过滤词表的,通常进行过滤的代码如下

        (字符串文档:文档){   (字符串filterWord: filterWords) {   如果(document.contains (filterWord)) {//过程……   }   }   }      

如果文本的数量是n,过滤词的数量是k,那么复杂度为O (nk);如果关键词的数量较多,那么支行效率是非常低的。

  

计算机科学中,Aho-Corasick算法是由AlfredV.Aho和MargaretJ.Corasick发明的字符串搜索算法,用于在输入的一串字符串中匹配有限组”字典”中的子串。它与普通字符串匹配的不同点在于同时与所有字典串进行匹配。算法均摊情况下具有近似于线性的时间复杂度,约为字符串的长度加所有匹配的数量。然而由于需要找到所有匹配数,如果每个子串互相匹配(如字典为a, aa、aaa, aaaa级,输入的字符串为aaaa级),算法的时间复杂度会近似于匹配的二次函数。

  

  

在一般的情况下,针对一个文本进行关键词匹配,在匹配的过程中要与每个关键词一一进行计算。也就是说,每与一个关键词进行匹配,都要重新从文档的开始到结束进行扫描.AC自动机的思想的是,在开始时先通过词表,对以下三种情况进行缓存:

  

按照字符转移成功进行跳转成功(表)

  

按照字符转移失败进行跳转(失败表)

  

匹配成功输出表(输出表)

  

因此在匹配的过程中,无需从新从文档的开始进行匹配,而是通过缓存直接进行跳转,从而实现近似于线性的时间复杂度。

  

  

构建的过程分三个步骤,分别对成功表,表失败,输出表进行构建。其输出表中在构建成功和失败表进行都进行了补充fail表是一对一的,输出表是一对多的。

  

按照字符转移成功进行跳转成功(表)

  

成功表实际就是一棵trie树,构建的方式和trie树是一样的,这里就不赘述。

  

按照字符转移失败进行跳转(失败表)

  

设这个节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为C的节点。然后把当前节点的失败指针指向那个字母也为C的儿子。如果一直走到了根都没找的到,那就把失败指针指向根。使用广度优先搜索BFS,层次遍历节点来处理,每一个节点的失败路径。

  

匹配成功输出表(输出表)

  

  

举例说明,按顺序先后添加关键词,他,她,他的,她的。在匹配招待过程中。先构建三个表,如下图,实线是成功表,虚线是表失败,结点后的单词是ourput表。

  

多模字符串匹配算法原理及Java实现代码

  

代码         进口java.util。*;/* *   */公开课ACTrie {   私人布尔failureStatesConstructed=false;//是否建立了表失败   私人根节点;//根结点   公共ACTrie () {   这一点。根=新节点(真正的);   }/* *   *添加一个模式串   * @param关键字   */公共空间addKeyword(字符串字){   如果(关键字==null | | keyword.length ()==0) {   返回;   }   节点现状后=this.root;   (人物性格:keyword.toCharArray ()) {   现状后=currentState.insert(字符);   }   currentState.addEmit(关键字);   }/* *   *模式匹配   *   * @param文本待匹配的文本   * @return匹配到的模式串   */公共CollectionparseText(字符串文本){   checkForConstructedFailureStates ();   节点现状后=this.root;   List,collectedEmits=new ArrayList<的在();   for (int位置=0;位置& lt;text.length ();位置+ +){   人物性格=text.charAt(位置);   现状后=currentState.nextState(字符);   Collection发出=currentState.emit ();   如果(发出==null | | emits.isEmpty ()) {   继续;   }   (字符串排放:排放){   collectedEmits。添加(新排放(位置- emit.length() + 1,位置,发出));   }   }   返回collectedEmits;   }/* *   *检查是否建立了表失败   */私人空间checkForConstructedFailureStates () {   如果(! this.failureStatesConstructed) {   constructFailureStates ();   }   }/* *   *建立表失败   */私人空间constructFailureStates () {   Queue

多模字符串匹配算法原理及Java实现代码