我正在编写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中最快的循环结构,并且因为以何种顺序处理单词并不重要,因此循环速度的确是唯一的考虑因素。
我希望这会有所帮助,如果不是,那至少是一个有趣的练习。 :)