首页
社区
课程
招聘
[原创]内存特征码搜索_字符串匹配算法_Boyer-Moore思想的实现_CPP源码分享
发表于: 2021-9-12 11:26 8847

[原创]内存特征码搜索_字符串匹配算法_Boyer-Moore思想的实现_CPP源码分享

2021-9-12 11:26
8847

早些年就玩过内存特征码搜索,
学习过Sunday,必须他理解最简单
然后写了个X86 X64通用特征码匹配
发帖这边
https://www.chinapyg.com/thread-98948-1-1.html
然后又把kmp学了一下,分享这边
https://www.chinapyg.com/thread-135745-1-1.html
现在闲着把BM的思想也理解了一下,
参考了一些先人的写法逻辑,终于感觉能写出来了
把搜索的那几种算法都玩一次,

暴力就不说了
kmp:我的理解就是最简单的匹配失败后,尝试不断向后推进,记录这个尝试结果,用于后续
sunday : 利用hash表开放式寻址,直接定位char的定长256,记录子串字符出现最后一个位置来推进
Boyer-Moore :这个大多数文章都只有思路,坏字符应该就说的Sunday方式,而好字符应该就是kmp这类思路,从子串推进,然后结合2者

我就把这2者结合来写了,
主要推进Sunday也就是坏字符的思路,
加入kmp之类的好字符思路兜底,
因为只是兜底所以没有去跟坏字符比长度取最大来推进,
毕竟对比再去最大,这花销,好多时候达到的推进估计补不回来,
所以我就直接推进kmp改进后的表了,不去对比取最大,节约点开销

听说玩这些的估计不会有易语言玩家,
所以我特别改了个英文版来发
源码如下:

 
 
 
intptr_t BM_find(const char* t, size_t lt, const char* s, size_t ls)
{
    //建立跳转表
    size_t* Tpkmp = new size_t[ls];
    intptr_t k = 0, coiled = 1;
    //计算子串特征_[next表]
    for (size_t i = 1; i < ls; i++)
    {
        if (s[i] == s[k]) { ++k; }
        else { k = (s[i] == s[0]) ? 1 : 0; }
        Tpkmp[i - 1] = i - k;
    }
    //优化表
    k = -1;
    for (size_t i = 0; i < ls - 1; i++)
    {
        if (s[i] == s[ls - 1]) { k = i; }
        if (s[i] == s[i + 1] && coiled)
        {
            Tpkmp[i + 1] = Tpkmp[i] > ++coiled ? Tpkmp[i] : coiled;
        }
        else
        {
            coiled = 0;
        }
 
    }
    Tpkmp[0] = ls - k - 1;
    for (size_t i = 1; i < ls; i++)
    {
        if (Tpkmp[ls - i] < Tpkmp[0]) { Tpkmp[ls - i] = Tpkmp[0]; }
    }
    //开始制作哈希表
    char Thash[256];
    for (size_t i = 0; i < 256; i++) { Thash[i] = ls; }
    for (size_t i = 0; i < ls; i++) { Thash[(size_t)s[i] & 0xff] = ls - 1 - i; }
    //制表到此完成
    ls -= 1;
    lt -= ls;
    intptr_t out = -1;
    //开始遍历搜索
    for (size_t i = 0; i < lt;)
    {
        //坏字符
        if (Thash[(size_t) * (t + i + ls) & 0xff]) { i += Thash[(size_t) * (t + i + ls) & 0xff]; goto fail; }
        //好字符
        for (size_t n = 0; n < ls; n++)
        {
            if (*(t + i + n) != *(s + n)) { i += Tpkmp[n]; goto fail; }
        }
        //找到_结束循环
        out = i; break;
    fail:;
    }
    //收尾工作
    delete[] Tpkmp;
    return out;
}
intptr_t BM_find(const char* t, size_t lt, const char* s, size_t ls)
{
    //建立跳转表
    size_t* Tpkmp = new size_t[ls];
    intptr_t k = 0, coiled = 1;
    //计算子串特征_[next表]
    for (size_t i = 1; i < ls; i++)
    {
        if (s[i] == s[k]) { ++k; }
        else { k = (s[i] == s[0]) ? 1 : 0; }
        Tpkmp[i - 1] = i - k;
    }
    //优化表
    k = -1;
    for (size_t i = 0; i < ls - 1; i++)
    {
        if (s[i] == s[ls - 1]) { k = i; }
        if (s[i] == s[i + 1] && coiled)
        {
            Tpkmp[i + 1] = Tpkmp[i] > ++coiled ? Tpkmp[i] : coiled;
        }
        else
        {
            coiled = 0;
        }
 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 8
支持
分享
最新回复 (8)
雪    币: 3729
活跃值: (4111)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
顶顺表哥,话说表哥好久没冒泡了,能说下需要那几个参数不?
2021-9-12 11:41
0
雪    币: 243
活跃值: (753)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
院士 顶顺表哥,话说表哥好久没冒泡了,能说下需要那几个参数不?[em_13]
主串,主串长度,子串,子串长度     四个参数
2021-9-12 12:37
0
雪    币: 4516
活跃值: (4493)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
void get_next(unsigned char* t , int tl, int* next) //获取回溯的表
{

	int len = tl;
	int i = 0;
	int j = -1;  //尾缀
	next[0] = -1; //前缀
	while (i < len)
	{
		if (j == -1 || t[i] == t[j])
		{
			j++;
			i++;

			//与普通KMP差异的地方
			if (t[i] != t[j])
			{
				next[i] = j;
			}
			else
			{
				next[i] = next[j];
				//这个主要是考虑匹配失败的时候,如果匹配失败了,必然往回回溯,但是如果回溯的下一个
				//地方还是这个元素,必然没有意义,还要往前回溯,那就把前一个元素的回溯值直接交给后面就可以了

				//比如  S = abacababc
				//		T = abab
				//匹配第四个元素不同,必然往前回溯,变成
				//      S = abacababc
				//		  T = abab
				//对着的还是b,不可能匹配成功的。
				//所以,如果有匹配的子串,而且其下一个元素也相同,那就意味着,如果下一个元素匹配失败的时候
				//往前回溯,对应元素还是这个值。
			}
			//差异结束

		}
		else
		{
			j = next[j]; 
		}
	}
}

int Index_KMP(unsigned char* S , int SLength, unsigned char* T , int TLength)
{
	int next[260]={0};
	get_next(T,TLength, next);//获取模式串用于标识回溯位置的表
	int i = 0;
	int j = 0;
	int Slen = SLength;//主串
	int Tlen = TLength; //模式串

	while (i < Slen && j < Tlen)
	{
		if (j == -1 || S[i] == T[j])
		{
			i++;
			j++;
		}
		else
		{
			j = next[j];
		}
	}
	if (j == Tlen)//匹配成功
	{
		return i - j;
	}
	else
	{
		return -1;
	}

}



也备用一个搜索代码. 方便以后查找.

最后于 2021-9-17 06:48 被Mxixihaha编辑 ,原因:
2021-9-17 06:47
0
雪    币: 6367
活跃值: (3897)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
你这是DLL吗?
2021-9-17 09:10
0
雪    币: 243
活跃值: (753)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
Mxixihaha void&nbsp;get_next(unsigned&nbsp;char*&nbsp;t&nbsp;,&nbsp;int&nbsp;tl,&n ...

听群里的表哥说这种回帖,就是要竞速的意思...

上2张,我自己测试的搜索速度对比,仁兄可自行试试,再接再厉

2021-9-19 00:37
0
雪    币: 243
活跃值: (753)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7

如果只是纯碎的想测试对kmp的优化,

可以改下搜索过程中的哈希表的坏字符的使用

改成如下,就是纯碎的kmp优化模式

优化的思想,基本在楼上pyg那边相关帖子说过了,不重复了

2021-9-19 00:54
0
雪    币: 15628
活跃值: (4280)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
BM不支持??搜索吧?
2021-9-19 11:56
0
雪    币: 10426
活跃值: (4586)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
支持楼主,可惜不支持通配符?
2021-9-19 13:41
0
游客
登录 | 注册 方可回帖
返回
//