因为项目中嵌入了spider monkey,需要做剪裁和扩展,因此对源码做了点研究。
在读String的实现的时候,发现str_IndexOf使用的字符串匹配算法就是著名的BMH算法,从实际效率考虑,并不是所有情况下都使用BMH算法,而是在如下情况下 if ((jsuint)(patlen - 2) <= BMH_PATLEN_MAX - 2 && textlen >= 512) 才使用,其余情况下则使用普通的遍历方法查找字符串。
patlen是匹配串长度,textlen是被匹配文本长度。BMH_PATLEN_MAX为255,是skip element的size,(uint8)。
前一个条件(jsuint)(patlen - 2) <= BMH_PATLEN_MAX - 2很好理解,patlen == 1的时候当然没必要使用BMH了,patlen > BMH_PATLEN_MAX 的时候 skip数组的元素长度不够。第2个条件textlen >= 512 似乎只能用实际的测试数据来说话了,简单的从复杂度来判断似乎说明不了什么。等有空找到典型的测试数据再补上来。
附上BMH算法,思想很简单,自己看代码就很容易理解了。
jsint
js_BoyerMooreHorspool(const jschar *text, jsint textlen,
const jschar *pat, jsint patlen,
jsint start)
{
jsint i, j, k, m;
uint8 skip[BMH_CHARSET_SIZE];
jschar c;
JS_ASSERT(0 < patlen && patlen <= BMH_PATLEN_MAX);
for (i = 0; i < BMH_CHARSET_SIZE; i++)
skip[i] = (uint8)patlen;
m = patlen - 1;
for (i = 0; i < m; i++) {
c = pat[i];
if (c >= BMH_CHARSET_SIZE)
return BMH_BAD_PATTERN;
skip[c] = (uint8)(m - i);
}
for (k = start + m;
k < textlen;
k += ((c = text[k]) >= BMH_CHARSET_SIZE) ? patlen : skip[c]) {
for (i = k, j = m; ; i--, j--) {
if (j < 0)
return i + 1;
if (text[i] != pat[j])
break;
}
}
return -1;
}
在读String的实现的时候,发现str_IndexOf使用的字符串匹配算法就是著名的BMH算法,从实际效率考虑,并不是所有情况下都使用BMH算法,而是在如下情况下 if ((jsuint)(patlen - 2) <= BMH_PATLEN_MAX - 2 && textlen >= 512) 才使用,其余情况下则使用普通的遍历方法查找字符串。
patlen是匹配串长度,textlen是被匹配文本长度。BMH_PATLEN_MAX为255,是skip element的size,(uint8)。
前一个条件(jsuint)(patlen - 2) <= BMH_PATLEN_MAX - 2很好理解,patlen == 1的时候当然没必要使用BMH了,patlen > BMH_PATLEN_MAX 的时候 skip数组的元素长度不够。第2个条件textlen >= 512 似乎只能用实际的测试数据来说话了,简单的从复杂度来判断似乎说明不了什么。等有空找到典型的测试数据再补上来。
附上BMH算法,思想很简单,自己看代码就很容易理解了。
jsint
js_BoyerMooreHorspool(const jschar *text, jsint textlen,
const jschar *pat, jsint patlen,
jsint start)
{
jsint i, j, k, m;
uint8 skip[BMH_CHARSET_SIZE];
jschar c;
JS_ASSERT(0 < patlen && patlen <= BMH_PATLEN_MAX);
for (i = 0; i < BMH_CHARSET_SIZE; i++)
skip[i] = (uint8)patlen;
m = patlen - 1;
for (i = 0; i < m; i++) {
c = pat[i];
if (c >= BMH_CHARSET_SIZE)
return BMH_BAD_PATTERN;
skip[c] = (uint8)(m - i);
}
for (k = start + m;
k < textlen;
k += ((c = text[k]) >= BMH_CHARSET_SIZE) ? patlen : skip[c]) {
for (i = k, j = m; ; i--, j--) {
if (j < 0)
return i + 1;
if (text[i] != pat[j])
break;
}
}
return -1;
}