参考链接:http://www.cnblogs.com/zzqcn/p/3525636.html

感谢原文作者。

花了两天半时间实现并测试了算法。

按照上文的思路实现了一遍,可能是原文中有些地方描述的不是特别清楚,导致一开始测试的时候发现了各种匹配遗漏的情况,后经过自己各种努力终于解决了各种遗漏。

同时在实现过程中也遇到了各种小问题,最后都解决了,总结起来主要有四个大坑,自己实现的时候需要注意,四个坑都在代码的注释里面了。

这里的实现虽然不会有遗漏的情况,但会有同一模式串在相同的偏移多次被命中的情况,但无伤大雅,至少没有遗漏不是吗。实际应用中只需对结果做去重就好了。

测试结论:对一个101.3MB的PE,从中随机抽取长度在[16-116)Bytes的模式串16个,分别用memcmp方式和AC自动机方式进行匹配,memcmp方式耗时33秒,AC方式耗时12秒,可见优势还是比较明显的。

代码中如有哪里不对,欢迎一起讨论。

 #include <cstdlib>
#include <cstdio>
#include <cstring>
#include <stdint.h>
#include <vector>
#include <map>
#include <queue>
#include <ctime> typedef struct ACNode
{
uint64_t u64Depth;
struct ACNode *pFail;
std::map<unsigned char, struct ACNode *> *pmpGotoTab;
struct ACParrent
{
struct ACNode *pParent;
unsigned char ucCondition;
} Parent;
bool bIsMathed;
} AC_NODE, *P_AC_NODE; typedef void (__stdcall *P_AC_FOUND_CALLBACK)(const unsigned char *In_pucBuf, uint64_t In_u64EndPos, uint64_t In_u64Len); int InitACGoto(const std::vector<const std::vector<unsigned char> *> &In_vctPattern,
std::vector<P_AC_NODE> &Out_vctACNodes)
{
int iRetVal = ;
P_AC_NODE pRoot = NULL;
unsigned int uiPattIdx = ;
unsigned int uiUCharIdx = ;
uint16_t u16Idx = ; if (In_vctPattern.empty())
{
iRetVal = -;
goto fun_ret;
} pRoot = (P_AC_NODE)calloc(, sizeof(AC_NODE));
if (pRoot == NULL)
{
iRetVal = -;
goto fun_ret;
} pRoot->pmpGotoTab = new std::map<unsigned char, struct ACNode *>();
for (u16Idx = ; u16Idx <= 0xff; u16Idx ++)
pRoot->pmpGotoTab->insert(std::pair<unsigned char, struct ACNode *>((unsigned char)u16Idx, pRoot));
Out_vctACNodes.push_back(pRoot); for (uiPattIdx = ; uiPattIdx < In_vctPattern.size(); uiPattIdx ++)
{
P_AC_NODE pCurNode = pRoot;
for (uiUCharIdx = ; uiUCharIdx < In_vctPattern[uiPattIdx]->size(); uiUCharIdx ++)
{
unsigned char ucCurUChar = In_vctPattern[uiPattIdx]->at(uiUCharIdx);
if (pCurNode->pmpGotoTab->find(ucCurUChar) == pCurNode->pmpGotoTab->end()
|| (pCurNode->pmpGotoTab->find(ucCurUChar) != pCurNode->pmpGotoTab->end()
&& pCurNode->pmpGotoTab->at(ucCurUChar) == pRoot))
{
P_AC_NODE pNode = (P_AC_NODE)calloc(, sizeof(AC_NODE));
if (pNode == NULL)
{
iRetVal = -;
goto fun_ret;
} pNode->u64Depth = uiUCharIdx + ;
pNode->Parent.pParent = pCurNode;
pNode->Parent.ucCondition = ucCurUChar;
pNode->pmpGotoTab = new std::map<unsigned char, struct ACNode *>(); if (pCurNode->pmpGotoTab->find(ucCurUChar) != pCurNode->pmpGotoTab->end())
pCurNode->pmpGotoTab->erase(ucCurUChar);
pCurNode->pmpGotoTab->insert(std::pair<unsigned char, struct ACNode *>(ucCurUChar, pNode));
pCurNode = pNode;
Out_vctACNodes.push_back(pNode);
}
else
pCurNode = pCurNode->pmpGotoTab->at(ucCurUChar); if (uiUCharIdx == In_vctPattern[uiPattIdx]->size() - )
pCurNode->bIsMathed = true;
}
} fun_ret:
return iRetVal;
} int ACFail(std::vector<P_AC_NODE> &Out_vctACNodes)
{
int iRetVal = ;
std::queue<P_AC_NODE> quNodes; if (Out_vctACNodes.empty())
{
iRetVal = -;
goto fun_ret;
} quNodes.push(Out_vctACNodes[]);
while (!quNodes.empty())
{
std::map<unsigned char, struct ACNode *>::iterator itGoto;
P_AC_NODE pNode = quNodes.front();
quNodes.pop();
if (pNode->u64Depth <= )
pNode->pFail = Out_vctACNodes[];
else
{
P_AC_NODE pParentFail = pNode->Parent.pParent->pFail;
while (pParentFail->pmpGotoTab->find(pNode->Parent.ucCondition) == pParentFail->pmpGotoTab->end())
pParentFail = pParentFail->pFail;
pNode->pFail = pParentFail->pmpGotoTab->at(pNode->Parent.ucCondition);
}
for (itGoto = pNode->pmpGotoTab->begin(); itGoto != pNode->pmpGotoTab->end(); itGoto ++)
{
if (itGoto->second != Out_vctACNodes[])
quNodes.push(itGoto->second);
}
} fun_ret:
return iRetVal;
} void __stdcall ACFoundCallBack(const unsigned char *In_pucBuf, uint64_t In_u64EndPos, uint64_t In_u64Len)
{
if (In_pucBuf == NULL || In_u64Len == )
goto fun_ret; printf("<<<<<<<<<<FUCKOFF:%x\n", In_u64EndPos - In_u64Len); fun_ret:
return;
} int ACSearch(const P_AC_NODE In_pRoot, const unsigned char *In_pucBuf, uint64_t In_u64BufLen, P_AC_FOUND_CALLBACK In_pfCallBack)
{
int iRetVal = ;
P_AC_NODE pCurrent = NULL;
uint64_t u64Idx = ; if (In_pRoot == NULL || In_pucBuf == NULL || In_u64BufLen == || In_pfCallBack == NULL)
{
iRetVal = -;
goto fun_ret;
} pCurrent = In_pRoot;
for (u64Idx = ; u64Idx < In_u64BufLen;)
{
P_AC_NODE pFail = NULL;
if (pCurrent->pmpGotoTab->find(In_pucBuf[u64Idx]) != pCurrent->pmpGotoTab->end())
{
pCurrent = pCurrent->pmpGotoTab->at(In_pucBuf[u64Idx]);
//坑1,出现匹配失败时不要前进,只在匹配成功时前进
u64Idx ++;
}
else
pCurrent = pCurrent->pFail; //坑3,每个节点都需要沿着失配指针一直向上找所有匹配到的结果,而不是
//只在匹配成功时才这么做,否则会出现匹配遗漏(形如“abcd”和“bc”这样的特征串并存的情况)
pFail = pCurrent->pFail;
//坑4,一定要走到根,否则会出现匹配遗漏
while (pFail != In_pRoot)
{
if (pFail->bIsMathed)
In_pfCallBack(In_pucBuf, u64Idx, pFail->u64Depth);
pFail = pFail->pFail;
}
//坑2,不管是否匹配成功,都要判断当前节点状态,因为出现失配后的
//转移也有可能转到一个成功匹配的节点上
if (pCurrent->bIsMathed)
In_pfCallBack(In_pucBuf, u64Idx, pCurrent->u64Depth);
} fun_ret:
return iRetVal;
} void ReleaseACNodes(std::vector<P_AC_NODE> &Out_vctACNodes)
{
unsigned int uiIdx = ;
for (uiIdx = ; uiIdx < Out_vctACNodes.size(); uiIdx ++)
{
delete Out_vctACNodes[uiIdx]->pmpGotoTab;
free(Out_vctACNodes[uiIdx]);
}
Out_vctACNodes.clear();
} void main(int argc, char **argv)
{
std::vector<P_AC_NODE> vctNodes;
std::vector<const std::vector<unsigned char> *> vctPatterns;
unsigned char *pucBuf = NULL;
FILE *pf = NULL;
long lFileSize = ;
time_t tACBegin = {};
double dMemSec = 0.0; pf = fopen(argv[], "rb");
fseek(pf, , SEEK_END);
lFileSize = ftell(pf);
fseek(pf, , SEEK_SET);
pucBuf = (unsigned char *)calloc(lFileSize, );
fread(pucBuf, , lFileSize, pf);
fclose(pf);
for (int i = ; i < ; i ++)
{
std::vector<unsigned char> *pvctPattern = new std::vector<unsigned char>();
int iBegin = rand() % (lFileSize - );
int iLen = rand() % + ;
for (int j = ; j < iLen; j ++)
pvctPattern->push_back(pucBuf[j + iBegin]);
vctPatterns.push_back(pvctPattern);
printf("%x:%u\n", iBegin, iLen);
for (long j = ; j < lFileSize - iLen; j ++)
{
time_t tMemBegin = time(NULL);
if (memcmp(pucBuf + iBegin, pucBuf + j, iLen) == )
printf(">>>>>>>>>>Off:%x\n", j);
dMemSec += difftime(time(NULL), tMemBegin);
}
} InitACGoto(vctPatterns, vctNodes);
ACFail(vctNodes);
tACBegin = time(NULL);
ACSearch(vctNodes[], pucBuf, lFileSize, ACFoundCallBack);
printf("MemTime::%f\nACTime::%f\n", dMemSec, difftime(time(NULL), tACBegin));
ReleaseACNodes(vctNodes);
return;
}

基于AC有限状态机的多模匹配算法的更多相关文章

  1. 基于Qt有限状态机的一种实现方式和完善的人工智能方法

    基于Qt有限状态机的一种实现方式和完善的人工智能方法 人工智能在今年是一个非常火的方向,当然了.不不过今年,它一直火了非常多年,有关人工智能的一些算法层出不穷.人工智能在非常多领域都有应用,就拿我熟悉 ...

  2. java实现多模匹配算法

    这个是好几年前写的了.都统一放到cnblogs上面. --------------------------------Node ---------------------------------- p ...

  3. 基于KMP与Levenshtein模糊匹配算法的银行联行号查询(转)

    在人民银行那里,每个银行的每一个营业网点都有自己唯一的银行联行号,根据这个号码能快速定位一间银行具体的分支行,就像根据一个身份证号码能快速确定一个人一样.例如汇款时,汇款单上要求填写收款人开户行,然后 ...

  4. 基于KMP与Levenshtein模糊匹配算法的银行联行号查询

    在人民银行那里,每个银行的每一个营业网点都有自己唯一的银行联行号,根据这个号码能快速定位一间银行具体的分支行,就像根据一个身份证号码能快速确定一个人一样.例如汇款时,汇款单上要求填写收款人开户行,然后 ...

  5. 基于Unity有限状态机框架

    这个框架是Unity wiki上的框架.网址:http://wiki.unity3d.com/index.php/Finite_State_Machine 这就相当于是“模板”吧,自己写的代码,写啥都 ...

  6. 多模匹配算法之Aho-Corasick

    除剔除那些含有敏感词的文本,由于有大量的敏感词,所以通过简单的正则表达式和字符串查找的方式效率太低,每次都有遍历一次字符串.而AC算法的核心思想就是避免不必要的回溯使搜索一直沿着向前的方向,最大可能的 ...

  7. POJ 3691 DNA repair 基于AC自己主动机DP

    dp[i][j] 它表示的长度 i 下游前缀 j 更改节点的最小数量. 很清楚dp[0][0] = 0; dp[ i ][ j ] = min(dp[ i ][ j ],dp[i-1][k] + (j ...

  8. AC多模式匹配算法

    建议:学习ac算法最好的途径是看论文pdf_Efficient_String_Matching_An_Aid_to_Biblio 一.一般的搜索算法 keyword: { he, she, his, ...

  9. 【工程应用一】 多目标多角度的快速模板匹配算法(基于NCC,效果无限接近Halcon中........)

    愿意写代码的人一般都不太愿意去写文章,因为代码方面的艺术和文字中的美学往往很难兼得,两者都兼得的人通常都已经被西方极乐世界所收罗,我也是只喜欢写代码,让那些字母组成美妙的歌曲,然后自我沉浸在其中自得其 ...

随机推荐

  1. Lakeshore 中文开发界面,示例项目,飞机大战 等 Lakeshore Chinese development interface, sample project, aircraft war, etc

    Lakeshore 中文开发界面,示例项目,飞机大战 等 Lakeshore Chinese development interface, sample project, aircraft war, ...

  2. Codeforces.600E.Lomsat gelral(dsu on tree)

    题目链接 dsu on tree详见这. \(Description\) 给定一棵树.求以每个点为根的子树中,出现次数最多的颜色的和. \(Solution\) dsu on tree模板题. 用\( ...

  3. LOJ.6284.数列分块入门8(分块)

    题目链接 \(Description\) 给出一个长为n的数列,以及n个操作,操作涉及区间询问等于一个数c的元素,并将这个区间的所有元素改为c. \(Solution\) 模拟一些数据可以发现,询问后 ...

  4. JAVA中验证邮箱是否有效

    String email = form.getEmail(); if(!email.matches("^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\\.[a-zA ...

  5. Convert a VMDK (VMWare) file to VHDX (Hyper-V)

    https://www.meziantou.net/2016/09/09/convert-a-vmdk-vmware-file-to-vhdx-hyper-v Microsoft provides a ...

  6. 以添加评论组件为例看angular2请求数据的处理

    在NiceFish项目中,数据请求处理并没有用Promise的那一套方法,用的是Observable(观察者模式),我将其理解成生产者和消费者模式 如下简单例子:出自(https://segmentf ...

  7. PHP Redis 对象方法手册

    redis(Remote Dictionary Server)是一种Nosql技术,它是一个开源的高级kv存储和数据结构存储系统. redis不仅仅是能够存储key和value这种简单的键值对,还能存 ...

  8. Django的使用规则

    ORM应该算是Python的一大特色,功能类似于Mybatis或hibernate,但是显示要强大更多 一:terminal下命令行的使用 1.创建一个Project django-admin sta ...

  9. python:函数的高级特性

    很多语言中,都允许把函数本身做为参数,传递给其它参数:即所谓的高阶函数.python中也有类似特性: 一.map/reduce.filter.sorted hadoop里的map-reduce思想在p ...

  10. AngularJS中$interval的用法

    在AngularJS中$interval用来处理间歇性处理一些事情. 最常用的是: var app = angular.module("app",[]); app.controll ...