算法原理这里不废话,网上找到的算法很多再临界情况的处理都有错误,所以自己重写了一个。
预处理创建shift资源表时的效率比较一般,但是简单易懂! 如果你有更好的版本希望发来研究研究。
/* * Boyer-Moore 精确匹配算法 * ------------------------------------------- * copyright (c) 2012 Niu Chenguang <[email protected]> * * 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__