原文地址:http://ouyangjia7.javaeye.com/blog/353137
#include "messageFormat.h"
#include <iostream>
using namespace std;
/*int processFile();
{
}*/
/*
函數:int* MakeSkip(char *, int)
目的:根據壞字元規則做預先處理,建立一張壞字元表
參數:
ptrn => 模式串P
PLen => 模式串P長度
返回:
int* - 壞字元表
*/
int* MakeSkip(char *ptrn, int pLen)
{
int i;
//為建立壞字元表,申請256個int的空間
/*PS:之所以要申請256個,是因為一個字元是8位,
所以字元可能有2的8次方即256種不同情況*/
int *skip = (int*)malloc(256*sizeof(int));
if(skip == NULL)
{
fprintf(stderr, "malloc failed!");
return 0;
}
//初始化壞字元表,256個單元全部初始化為pLen
for(i = 0; i < 256; i++)
{
*(skip+i) = pLen;
}
//給表中需要賦值的單元賦值,不在模式串中出現的字元就不用再賦值了
while(pLen != 0)
{
*(skip+(unsigned char)*ptrn++) = pLen--;
}
return skip;
}
/*
函數:int* MakeShift(char *, int)
目的:根據好尾碼規則做預先處理,建立一張好尾碼表
參數:
ptrn => 模式串P
PLen => 模式串P長度
返回:
int* - 好尾碼表
*/
int* MakeShift(char* ptrn,int pLen)
{
//為好尾碼表申請pLen個int的空間
int *shift = (int*)malloc(pLen*sizeof(int));
int *sptr = shift + pLen - 1;//方便給好尾碼表進行賦值的指標
char *pptr = ptrn + pLen - 1;//記錄好尾碼表邊界位置的指標
char c;
if(shift == NULL)
{
fprintf(stderr,"malloc failed!");
return 0;
}
c = *(ptrn + pLen - 1);//儲存模式串中最後一個字元,因為要反覆用到它
*sptr = 1;//以最後一個字元為邊界時,確定移動1的距離
pptr--;//邊界移動到倒數第二個字元(這句是我自己加上去的,因為我總覺得不加上去會有BUG,大家試試“abcdd”的情況,即末尾兩位重複的情況)
while(sptr-- != shift)//該最外層迴圈完成給好尾碼表中每一個單元進行賦值的工作
{
char *p1 = ptrn + pLen - 2, *p2,*p3;
//該do...while迴圈完成以當前pptr所指的字元為邊界時,要移動的距離
do{
while(p1 >= ptrn && *p1-- != c);//該空迴圈,尋找與最後一個字元c匹配的字元所指向的位置
p2 = ptrn + pLen - 2;
p3 = p1;
while(p3 >= ptrn && *p3-- == *p2-- && p2 >= pptr);//該空迴圈,判斷在邊界內字元匹配到了什麼位置
}while(p3 >= ptrn && p2 >= pptr);
*sptr = shift + pLen - sptr + p2 - p3;//儲存好尾碼表中,以pptr所在字元為邊界時,要移動的位置
/*
PS:在這裡我要聲明一句,*sptr = (shift + pLen - sptr) + p2 - p3;
大家看被我用括弧括起來的部分,如果只需要計算字串移動的距離,那麼括弧中的那部分是不需要的。
因為在字串自左向右做匹配的時候,指標是一直向左移的,這裡*sptr儲存的內容,實際是指標要移動
距離,而不是字串移動的距離。我想SNORT是出於效能上的考慮,才這麼做的。
*/
pptr--;//邊界繼續向前移動
}
return shift;
}
/*
函數:int* BMSearch(char *, int , char *, int, int *, int *)
目的:判斷文本串T中是否包含模式串P
參數:
buf => 文本串T
blen => 文本串T長度
ptrn => 模式串P
PLen => 模式串P長度
skip => 壞字元表
shift => 好尾碼表
返回:
int - 1表示成功(文本串包含模式串),0表示失敗(文本串不包含模式串)。
*/
bool BMSearch(char *ptrn,char *buf)
{
int plen = strlen(ptrn);
int b_idx = plen;
int blen = strlen(buf);
if (plen == 0)
return false;
int *skip = MakeSkip(ptrn,plen);
int *shift = MakeShift(ptrn,plen);
while (b_idx <= blen)//計算字串是否匹配到了盡頭
{
int p_idx = plen, skip_stride, shift_stride;
while (buf[--b_idx] == ptrn[--p_idx])//開始匹配
{
if (b_idx < 0)
return false;
if (p_idx == 0)
{
return true;
}
}
skip_stride = skip[(unsigned char)buf[b_idx]];//根據壞字元規則計算跳躍的距離
shift_stride = shift[p_idx];//根據好尾碼規則計算跳躍的距離
b_idx += (skip_stride > shift_stride) ? skip_stride : shift_stride;//取大者
}
return false;
}
int main()
{
char *ptr = "465789";
char *buf = "789456465789";
if ( BMSearch(ptr,buf) )
{
cout<<"find OK"<<endl;
}
}