算法原理这里不废话,网上找到的算法很多再临界情况的处理都有错误,所以自己重写了一个。
预处理创建shift资源表时的效率比较一般,但是简单易懂! 如果你有更好的版本希望发来研究研究。
/*
* Boyer-Moore 精确匹配算法
* -------------------------------------------
* copyright (c) 2012 Niu Chenguang <chrisniu1984@gmail.com>
*
* file: bm.h
*/
#ifndef __BM_H__
#define __BM_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BM_SKIP_SIZE 256
#define BM_SHIFT_SIZE 128 // 此值决定字串最大长度
/*
* 为已知字符串创建skip资源表。
*
* @skip: [in/out] 存储skip资源的int数组。元素数必须为BM_SIKP_SIZE个。
* @sub: [in] 已知字符串
* @sub_len: [in] 字符串长度
*
* @RETURN: 0 = 成功,-1 = 失败
*/
static inline int bm_make_skip(int skip[], unsigned char *sub, int sub_len)
{
if (NULL == skip || NULL == sub || sub_len <= 0) {
return -1;
}
memset(skip, 0x00, sizeof(int)*BM_SKIP_SIZE);
int i;
for (i=0; i<BM_SKIP_SIZE; i++) {
skip[i] = sub_len;
}
while (sub_len != 0) {
skip[*sub] = --sub_len;
sub++;
}
return 0;
}
/*
* 为已知字符串创建shift资源表。
*
* @shift: [in/out] 存储shift资源的int数组。元素数必须为BM_SHIFT_SIZE个。
* @sub: [in] 已知字符串
* @sub_len: [in] 字符串长度
*
* @RETURN: 0 = 成功,-1 = 失败
*/
static inline int bm_make_shift(int shift[], unsigned char* sub,int sub_len)
{
if (NULL == shift || NULL == sub ||
sub_len <= 0 || sub_len > BM_SHIFT_SIZE) {
return -1;
}
memset(shift, 0x00, sizeof(int)*BM_SHIFT_SIZE);
int pos;
for (pos = sub_len-1; pos >= 0; pos--) {
//int i=0;
//printf("---------------------\n");
//printf("%s\n", sub);
//for (i=0; i<pos; i++) {
// printf(" ");
//}
//printf("%s\n", sub+pos);
unsigned char *good = sub + pos + 1; // 好后缀起始位置。
int good_len = sub_len - pos - 1; // 好后缀长度
// 此循环是为了匹配到尽量长的好后缀串
while (good_len > 0) {
// p 为开始位置查找好后缀
unsigned char *p = sub + sub_len - 1 - good_len;
// 此循环是为了从右向左逐个位置查找好后缀串。
while (p >= sub) {
// 在p位置找到了good
if (memcmp(p, good, good_len) == 0) {
shift[pos] = (sub_len-pos)+(good-p)-1;
break;
}
// 向左移动一个位置,准备继续查找good串
p--;
}
// 此shift位置有值,说明查找成功,直接break
if (shift[pos] != 0) {
break;
}
// 取好后缀的子串
good++;
good_len--;
}
// 此shift位置没有值,说明没有匹配到good串及其字串
if (shift[pos] == 0) {
shift[pos] = sub_len-pos;
}
//for(i=0;i<shift[pos]-(sub_len-pos);i++){
// printf(" ");
//}
//printf("%s\n", sub);
}
return 0;
}
static inline int bm_search(unsigned char *str, int str_len,
unsigned char *sub, int sub_len,
int skip[], int shift[])
{
if (sub_len == 0) {
return 1; // 根据实际需要,修改这个返回值。
}
if (sub_len > str_len) {
return 0;
}
int str_end = sub_len - 1;
while (str_end <= str_len) {
int sub_end = sub_len-1;
while (str[str_end] == sub[sub_end]) {
if (sub_end == 0) {
return 1;
}
str_end--;
sub_end--;
}
int skip_stride = skip[str[str_end]];
int shift_stride = shift[sub_end];
str_end += MAX(skip_stride,shift_stride);
}
return 0;
}
#endif // __BM_H__