在javascript中搜索字符串的最快方法
我的页面上有一个隐藏的字段,用于存储以空格分隔的电子邮件列表。 在那个领域我最多可以收到500封电子邮件 如果给定的电子邮件已经存在于该列表中,那么最快的搜索方式是什么? 我需要在一个循环中搜索多封电子邮件在javascript中搜索字符串的最快方法,javascript,Javascript,我的页面上有一个隐藏的字段,用于存储以空格分隔的电子邮件列表。 在那个领域我最多可以收到500封电子邮件 如果给定的电子邮件已经存在于该列表中,那么最快的搜索方式是什么? 我需要在一个循环中搜索多封电子邮件 使用正则表达式查找匹配项 使用indexOf() 将列表转换为 javascript字典,然后 搜寻 如果这是完全相同的,请让我知道另一个问题。 谢谢 编辑: 谢谢大家的宝贵意见和回答。 基本上,我的用户有一个以db为单位的电子邮件列表(0-500)。 用户将看到自己的联系人列表。 然后,用
indexOf()
可能是最快的。请记住,您需要搜索两种可能的情况:
var existingEmails = "email1, email2, ...";
var newEmail = "somethingHere@email.com";
var exists = (existingEmails.indexOf(newEmail + " ") >= 0) || (existingEmails.indexOf(" " + newEmail ) > 0);
你问的问题有太多未说明的变量,我们无法回答。例如,您希望执行多少次此搜索?只有一次?一百次?这是一个固定的电子邮件列表,还是每次都会改变?您是通过页面加载电子邮件,还是通过AJAX加载电子邮件 如果您正在执行多个搜索,或者电子邮件加载了该页面,那么您最好创建一个名称字典,并使用Javascript in操作符 如果从某个页外源获取字符串,并且只搜索一次,那么
indexOf
可能会更好
在所有情况下,如果你真的关心速度,你最好进行一次测试
但是我会问“你为什么关心速度?”这是一个网页,在这个网页上,加载页面是以网络速度进行的;搜索以或多或少的本地处理器速度进行。这一次搜索不大可能对页面的行为产生明显的影响。这里有一点解释: 执行字典查找相对比较复杂-与(比如)有很多键时按键线性查找相比非常快,但比直接数组查找复杂得多。它必须计算密钥的散列,然后计算出应该在哪个bucket中,可能需要处理重复的散列(或重复的bucket),然后检查是否相等 和往常一样,为工作选择正确的数据结构——如果你真的可以通过索引到一个数组(或列表)中而逃脱,那么是的,这将非常快
以上内容摘自@Jon Skeet的一篇博文。答案是:视情况而定
- 这取决于你实际想要测量什么
- 这取决于你搜索的数量与你搜索的数量之间的关系
- 这取决于JavaScript实现。不同的实现通常具有完全不同的性能特征。这是“不要过早优化”规则特别适用于跨实现JavaScript的众多原因之一
String 35; indexOf
,除非您可以创建一次字典并重用它(不仅仅是查找X个条目的一个循环,而是查找X个条目的每个循环,我倾向于怀疑这是您的用例),在这种情况下,构建500键字典并使用它会更快
我整理了一个示例,比较了在一个包含500个空格分隔的唯一条目的字符串中查找五个字符串的结果。请注意,jsperf页面比较了一些苹果和橙子(我们可以忽略设置的情况以及我们忽略的设置类型),但是jsperf对于拆分它来说是一件痛苦的事情,我决定把它作为一个练习留给读者
在我对你所做的测试中,Chrome、Firefox、IE6、IE7和IE9做的String#indexOf
最快。Opera执行了RegExp交替
最快的操作。(请注意,IE6和IE7没有数组#indexOf
,其他的都有。)如果您可以忽略字典设置时间,那么使用字典就是轻而易举的赢家
以下是准备代码:
// ==== Main Setup
var toFind = ["aaaaa100@zzzzz", "aaaaa200@zzzzz", "aaaaa300@zzzzz", "aaaaa400@zzzzz", "aaaaa500@zzzzz"];
var theString = (function() {
var m, n;
m = [];
for (n = 1; n <= 500; ++n) {
m.push("aaaaa" + n + "@zzzzz");
}
return m.join(" ");
})();
// ==== String#indexOf (and RegExp) setup for when we can ignore setup
var preppedString = " " + theString + " ";
// ==== RegExp setup for test case ignoring RegExp setup time
var theRegExp = new RegExp(" (?:" + toFind.join("|") + ") ", "g");
// ==== Dictionary setup for test case ignoring Dictionary setup time
var theDictionary = (function() {
var dict = {};
var index;
var values = theString.split(" ");
for (index = 0; index < values.length; ++index) {
dict[values[index]] = true;
}
return dict;
})();
// ==== Array setup time for test cases where we ignore array setup time
var theArray = theString.split(" ");
字符串#indexOf
(忽略设置)测试,在该测试中,我们忽略在大字符串的两端放置空格的(小)开销:
var index;
for (index = 0; index < toFind.length; ++index) {
if (preppedString.indexOf(toFind[index]) < 0) {
throw "Error";
}
}
RegExp
交替(忽略设置)测试,我们忽略设置RegExp对象和在大字符串两端放置空格所需的时间(我认为这不适用于您的情况,您要查找的地址是静态的):
字典测试:
var index;
for (index = 0; index < toFind.length; ++index) {
if (theString.indexOf(toFind[index]) < 0) {
throw "Error";
}
}
// Note: In real life, you'd have to escape the values from toFind
// to make sure they didn't have special regexp chars in them
var regexp = new RegExp(" (?:" + toFind.join("|") + ") ", "g");
var match, counter = 0;
var str = " " + theString + " ";
for (match = regexp.exec(str); match; match = regexp.exec(str)) {
++counter;
}
if (counter != 5) {
throw "Error";
}
var dict = {};
var index;
var values = theString.split(" ");
for (index = 0; index < values.length; ++index) {
dict[values[index]] = true;
}
for (index = 0; index < toFind.length; ++index) {
if (!(toFind[index] in dict)) {
throw "Error";
}
}
Array#indexOf
测试(注意,一些非常旧的JavaScript实现可能没有Array#indexOf
):
与其寻找最快的解决方案,您首先需要确保您实际拥有一个正确的解决方案。因为有四种情况会出现电子邮件地址,而简单的搜索可能会失败:
user@example.com
user@example.com…
。。。user@example.com
。。。user@example.com…
RegExp.quote = function(str) {
return str.toString().replace(/(?=[.?*+^$[\]\\(){}-])/g, "\\");
};
要匹配所有四种情况,可以使用以下模式:
/(?:^|\ )user@example\.com(?![^\ ])/
因此:
indexOf
稍微复杂一些,因为您需要手动检查边界:
var pos = haystack.indexOf(needle);
if (pos != -1 && (pos != 0 && haystack.charAt(pos-1) !== " " || haystack.length < (pos+needle.length) && haystack.charAt(pos+needle.length) !== " ")) {
pos = -1;
}
var inList = pos != -1;
现在要测试哪种变体最快,您可以在进行测试。我知道这是一个老问题,但这里有一个答案供未来可能需要的人使用
var index;
for (index = 0; index < toFind.length; ++index) {
if (theArray.indexOf(toFind[index]) < 0) {
throw "Error";
}
}
RegExp.quote = function(str) {
return str.toString().replace(/(?=[.?*+^$[\]\\(){}-])/g, "\\");
};
/(?:^|\ )user@example\.com(?![^\ ])/
var inList = new RegExp("(?:^| )" + RegExp.quote(needle) + "(?![^ ])").test(haystack);
var pos = haystack.indexOf(needle);
if (pos != -1 && (pos != 0 && haystack.charAt(pos-1) !== " " || haystack.length < (pos+needle.length) && haystack.charAt(pos+needle.length) !== " ")) {
pos = -1;
}
var inList = pos != -1;
var dict = {};
haystack.match(/[^\ ]+/g).map(function(match) { dict[match] = true; });
var inList = dict.hasOwnProperty(haystack);
console.time('a');
var a=((Math.random()*1e8)>>0).toString(16);
for(var i=0;i<1000;++i)a=a+' '+((Math.random()*1e8)>>0).toString(16)+((Math.random()*1e8)>>0).toString(16)+((Math.random()*1e8)>>0).toString(16)+((Math.random()*1e8)>>0).toString(16);
console.timeEnd('a');
console.time('b');
var b=(' '+a).indexOf(((Math.random()*1e8)>>0).toString(16));
console.timeEnd('b');
console.log([a,b]);