我正在编写Firefox扩展。我想在当前网页上搜索一组单词,并计算每次出现的次数。仅当用户询问时才执行此活动,但仍必须相当快地进行。

我目前在BODY标签的innerHTML元素上使用indexOf,但是发现它太慢而无法以以下方式重复运行:

function wordcount(doc, match)
{
  var count = 0;
  var pos = 0;
  for(;;)
  {
    len=doc.indexOf(match, pos);
    if(len == -1)
    {
      break;
    }
    pos = len + match.length;
    count++;
  }
  return count;
}

var html = content.document.body.innerHTML.toLowerCase()

for(var i=0; i<keywords.length; i++)
{
  var kw = keywords[i];
  myDump(kw + ": " + wordcount(html, kw));
}


使用100个关键字,这大约需要10到20秒才能运行。有一些范围可以减少关键字的数量,但是仍然需要更快地运行。

有没有更明显的方法可以做到这一点?什么是最有效的方法?我有一些想法,但不愿对每个代码进行编码,而没有对我可以期望的性能有所了解:


浏览DOM而不是使用
innerHTML。这可能吗
更快或更慢?它会有
仅搜索文字的好处
内容。
逐字遍历文档
字,累加每个
单词的同时出现。
使用这种方法,我将不得不做
解析HTML需要更多的工作。


编辑:原来最慢的部分是myDump函数写入错误控制台。 h!尽管如此,我还是打算使用一些有趣的更有效的替代方法。

最佳答案

我不确定这是否是最快的,但是以下内容对我来说很快。

var words = document.body.innerHTML.replace(/<.*?>/g,'').split(/\s+/);
var i = words.length;
var keywordCounts = {'keyword': 0, 'javascript': 0, 'today': 0};
var keywords = [];
var keywordMatcher = '';
var word;
for (word in keywordCounts) {
    keywords[keywords.length] = word ;
    keywordMatcher = keywordMatcher + '(' + word + ')?';
}
var regex = new RegExp(keywordMatcher);
var j = keywords.length;
var matched, keyword;
if (i && j) {
    do {
        i = i - 1;
        matched = words[i].match(regex);
        if (!matched) continue;
        j = keywords.length;
        do {
            j = j - 1;
            if (matched[j + 1]) {
                keyword = keywords[j];
                keywordCounts[keyword] = keywordCounts[keyword] + 1;
            }
        } while (j);
    } while (i);
}


从Big(O)角度来看,我绝对会认为这不是最好的,因为随着i和j变大,它仍然需要n平方的时间,但是我发现正则表达式处理通常非常快。

基本上,我会采用tvanfosson的想法并对其进行扩展,但不是遍历DOM,而是使用正则表达式(第一行)删除标签,然后将页面拆分为单个单词。关键字“哈希”在第三行定义为初始计数(显然它们都应从零开始)。从那里,我使用每个关键字作为一个组构造了一个新的正则表达式,因此当匹配时,它将返回一个数组(在我的示例中)为[fullMatch,keywordMatch,javascriptMatch,todayMatch]。我使用递减的do while循环,是因为在很多地方它们已被证明是JavaScript中最快的循环结构,并且因为以何种顺序处理单词并不重要,因此循环速度的确是唯一的考虑因素。

我希望这会有所帮助,如果不是,那至少是一个有趣的练习。 :)

10-07 12:31