BM字符串匹配算法的java实现
为了方便自己下次查找,以博文形式记录
本文只提供BM字符串匹配算法的java实现,其原理请看其他文章,CSDN里有讲得很好的
/**
* 函数建立一张坏字符表
* pstr: 模式串
* @param pstr
*/
public static int[] badCharacterSkip(String pstr) {
int i;
/*PS:之所以要申请256个int空间,是因为一
* 个字符是8位,所以字符可能有2^8=256种不同的情况
* */
int[] skip = new int[256];
//初始化坏字符表,256个单元全部初始化为模式串长度
for(i = 0; i < 256; i++) {
skip[i] = pstr.length();
}
i = pstr.length();
int j = 0;
/**
* 给表中需要赋值的单元赋值,但字符不在模式串pstr中时
* 应该移动pstr.length()个单位,如果字符在pstr中则移动的位置应
* 当是pstr.length()-最右索引index
*/
while(i != 0) {
skip[(int)pstr.charAt(j)] = i--;
j++;
}
return skip;
}
/**
* 该函数根据好后缀规则做预处理,建立一张好后缀表
* @param pstr
* @return
*/
public static int[] goodSuffixShift(String pstr) {
//模式串长度plen
int plen = pstr.length();
//好后缀表
int[] shift = new int[plen];
//记录给好后缀表赋值的位置
int sIndex = plen - 1;
//记录好后缀表边界的位置
int pIndex = plen - 1;
char c;
//保存模式串中最后一个字符,因为要反复用到它
c = pstr.charAt(plen - 1);
//以最后一个字符为边界时,确定移动距离为1
shift[plen - 1] = 1;
pIndex--;
//给shift表的每一个单元赋值
while(sIndex-- != 0) {
int p1 = plen - 2, p2, p3;
//该do...while循环完成以pIndex索引为边界时要移动的距离
do {
//该空循环,寻找与最后一个字符c匹配的字符的位置
while(p1 >= 0 && pstr.charAt(p1--) != c);
p2 = plen - 2;
p3 = p1;
//该空循环判断在边界内字符匹配到了什么位置
while(p3 >= 0 && pstr.charAt(p3--) == pstr.charAt(p2--) && p2 >= pIndex);
}while(p3 >= 0 && p2 >= pIndex);
//保存好好后缀表中,以pIndex为边界时,要移动的位置
shift[sIndex] = plen - sIndex + p2 - p3;
//边界继续向前移动
pIndex --;
}
return shift;
}
/**
* buf:文本串
* pstr: 模式串
* @param buf
* @param pstr
* @return
*/
public static boolean BMSearch(String buf, String pstr) {
int[] skip = badCharacterSkip(pstr);
int[] shift = goodSuffixShift(pstr);
int plen = pstr.length();
int blen = buf.length();
int b_idx = plen;
if(plen == 0)
return true;
//如果文本串没到达尽头
while(b_idx <= blen) {
int p_idx = plen, skip_stride, shift_stride;
//开始匹配
while(buf.charAt(--b_idx) == pstr.charAt(--p_idx)) {
if(b_idx < 0)
return false;
if(p_idx == 0) {
return true;
}
}
//根据坏字符规则计算跳跃的距离
skip_stride = skip[(int)buf.charAt(b_idx)];
//根据好后缀规则计算跳跃的距离
shift_stride = shift[p_idx];
//取大者
b_idx += (skip_stride > shift_stride) ? skip_stride : shift_stride;
}
return false;
}