有效搜索更大字符串中的许多子字符串之一

时间:2011-11-01 01:22:22

标签: javascript algorithm parsing

我正在寻找一个函数,它在一个较长的字符串('haystack')中找到一个字符串数组('needle')的子字符串。基本上我希望它像这个例子一样工作:

var haystack = "abcdefghijklmnopqrstuvwxyz";
var needles = [
  'bcd',
  'pqr',
  'hi',
  'ghi',
  'g',
  'stuv'
  ];

var output = findSubstring (haystack, needles, 2, 20);

输出现在应该有:

 {index: 6, which: 3}

这意味着它在位置6处找到了“ghi”(针3)。它得到'ghi'而不是'hi',因为'ghi'在大海捞针中较早开始,但它没有得到'g',因为' ghi'在针阵列中较早。

这是我提出的最好的,但是对于非常大的文本块和非常大的针阵列(我正在使用它),它似乎相当慢,我相信有更好的东西。这是非常重要的性能因素,所以我真的更喜欢更快的东西。

我可以想象更好的方法(可能不使用indexOf),并且因为这(很可能)是一种非常常见的事情,那些对这类事情有更多经验的人可能有更好的方法去关于它。 (即我宁愿不重新发明轮子)

function findSubstring (haystack, needles, startIndex, endIndex) {
  var min = Infinity, best = -1;
  var numNeedles = needles.length;
  if (!startIndex)
    startIndex = 0;

  for (var i=0; i<numNeedles; i++) {
    var index = haystack.indexOf(needles[i], startIndex);
    if (index != -1 && index < min) {
      min = index;
      best = i;
    }
  }
  return (best == -1 || (endIndex && best >= endIndex)) ?
      null : 
      {index: min, which: best};
}

6 个答案:

答案 0 :(得分:3)

建议将你的针头组合成一个正则表达式:“bcd | pqr | hi | ghi | g | stuv”。

正则表达式引擎将这些组合成一个有效的有限状态机。

答案 1 :(得分:1)

http://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm将找到它们出现的所有字符串。成本是要搜索的字符串的大小加上找到的每个匹配的常量,加上与要查找的字符串集大小成线性的设置时间。你需要添加额外的逻辑来丢弃你似乎不想要的匹配。

答案 2 :(得分:0)

通过第一个字符将子字符串排序为单独的数组...一个以'a'开头的单词数组,另一个用于'b'的数组,依此类推。

将您的字符串转换为数组。

通过数组解析,一次一个字符,检查每个相关的子串数组以进行匹配。如果可以提高性能,请使用二进制搜索来加速检查子串数组。

答案 3 :(得分:0)

不是为你要去的每个字符串反复调用indexOf,而是创建一个整数数组,在其中为每个字符串存储一次调用indexOf的结果。

之后,您只需找到数组中的最小数字(不是-1),这是字符串中的第一个匹配项。然后,您只需更新数组中小于匹配后字符的项(而不是-1)。重复直到到达字符串的末尾,或者数组中的所有项都是-1。

答案 4 :(得分:0)

如果heyStack将是一个非常大的文本,那么每次发现一个针时切断其余的heyStack“可能”更好:

if (index != -1 && index < min) {
    min = index;
    best = i;
    hayStack = hayStack.substring(0, index + indles[i].length);
}

答案 5 :(得分:0)

看看Knuth-Morris-Pratt算法,它可能对您的问题有用