Horspool是后缀搜索,也就是搜索已读入文本中是否含有模式串的后缀;如果有,是多长,显然,当后缀长度等于模式串的长度时,我们就找到了一个匹配。
Horspool算法认为:对于每个文本搜索窗口,将窗口内的最后一个字符(C)与模式串的最后一个字符进行比较。如果相等,则继续从后向前验证其他字符,直到完全相等或者某个字符不匹配。然后,无论匹配与否,都将根据在模式串的下一个出现位置将窗口向右移动。
匹配串:abcbcsdxzcxx
模式串:cbcac
这个时候我们从右向左进行对暗号,c-c,恩对上了,第二个b-a,不对啊,我们应该怎么办?难道就这么放弃么。于是,模式串从不匹配的那个字符开始从右向左寻找匹配串中不匹配的字符b的位置,结果发现居然有,赶快对上赶快对上,别耽误了。
匹配串:abcbcsdxzcxx
模式串: cbcac
然后继续从最右边的字符从右向左进行比较。这时候,我们发现了,d-c不匹配啊,而且模式穿里面没有噢,没办法,只好移动一个模式串长度的单位了。
匹配串:abcbcsdxzcxx
模式串: cbcac
判断模式串是否出现在源串的i位时,从i+m-1位开始比较,当比较到不同的时候。根据i+m-1位的内容对i作跳转。
如果i+m-1位的字符不在模式串中出现,则i+=m,
(这是因为i+m-1不在模式串里出现,则从i,i+1,i+m-1开始的串,都不可能完全匹配。)
否则寻找该字符在模式串中最后一次出现的位置,
如果最后一次是出现在最后一位,
则找再上一次的出现,如果找不到,则i+=m,
i += m-最后一次出现的位置
(原因是,完全匹配的时候,至少i+m-1是匹配的,所以这个移动是找最后的一个位置,使得i+m-1位匹配)
真正编程的时候,不用写这么多分支处理,直接在预处理的时候,用一个数组表示i每次要加上的数就行了。
1 int HorspoolMatch(byte* pSrc, int nSrcSize, byte* pSubSrc, int nSubSrcSize) 2 { 3 if (nSubSrcSize > nSrcSize) 4 { 5 return -1; 6 } 7 8 short skip[256]; 9 for(int i = 0; i < 256; i++) 10 { 11 skip[i] = nSubSrcSize; 12 } 13 for(int i = 0; i < nSubSrcSize - 1; i++) 14 { 15 skip[pSubSrc[i]] = nSubSrcSize - i - 1; 16 } 17 18 19 int pos = 0; 20 while(pos <= nSrcSize - nSubSrcSize) 21 { 22 int j = nSubSrcSize -1; 23 while(j >= 0 && pSrc[pos + j] == pSubSrc[j]) 24 { 25 j--; 26 } 27 if(j < 0 ) 28 { 29 break; 30 } 31 pos = pos + skip[pSrc[pos + nSubSrcSize -1]]; 32 } 33 return pos; 34 }