首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。KMP算法是单模式串的字符匹配算法,AC自动机是多模式串的字符匹配算法。
一、原理
AC自动机算法详解 》》 https://www.cnblogs.com/cmmdc/p/7337611.html
二、JavaScript代码
//javascript实现字典树trie,简单的实现下 class TrieNode { constructor(value){ this.value = value; //value为单个字符 this.num=1; this.deep=0;//根节点默认0 this.son=[]; this.isEnd=false; } findNode(value){ for(let i=0;i<this.son.length;i++){ const node=this.son[i] if(node.value == value){ return node; } } return null; } } class Trie { constructor(){ this.root=new TrieNode(null); this.size=1;//一开始的时候只有根节点这一个节点 } insert(str){ let node=this.root; for(let c of str){ let snode = node.findNode(c); if(snode==null){ snode=new TrieNode(c) snode.deep=node.deep+1; node.son.push(snode); }else{ snode.num++;//有N个字符串经过它 } node=snode; } //如果当前的node已经是一个word,则不需要添加 if (!node.isEnd) { this.size++; node.isEnd = true; } } has(str){ let node=this.root; for(let c of str){ const snode=node.findNode(c) if(snode){ node=snode; }else{ return false; } } return node.isEnd; } } //构建字典树失败指针 function build_ac_automation(root){ root.fail=null; const queue=[root] let i=0; while(i<queue.length){ const temp=queue[i]; for(let j=0;j<temp.son.length;j++){ const node=temp.son[j] if(temp===root){ node.fail=root; }else{ node.fail=temp.fail.findNode(node.value)||root; } queue.push(node); } i++ } } //ac算法多字符查询 function acSearch(arr,str) { //生成字典树 const tr=new Trie() arr.forEach(function (item) { tr.insert(item) }) //构造字典树的失败指针 build_ac_automation(tr.root) let node=tr.root; const data=[]; for(let i=0;i<str.length;i++){ let cnode=node.findNode(str[i]) //匹配不到字符,进入失败匹配, while(!cnode&&node!==tr.root){ node=node.fail; cnode=node.findNode(str[i]) } if(cnode){ node=cnode; } if(node.isEnd){ data.push({ start:i+1-node.deep, len:node.deep, str:str.substr(i+1-node.deep,node.deep), num:node.num, }) } } return data; } //test const result=acSearch(['she','shr','her','her'],'sher'); console.log(result); /** * [ { start: 0, len: 3, str: 'she', num: 1 }, { start: 1, len: 3, str: 'her', num: 2 } ] */