一个问题:
我想处理一个字符串(str
),以便任何带括号的数字(由rgx
匹配)替换为从数组中的适当位置取得的值(sub
):
var rgx = /\((\d+)\)/,
str = "this (0) a (1) sentence",
sub = [
"is",
"test"
],
result;
鉴于上面声明的变量,result
应该是'这是一个测试句'。
两个解决方案:
var mch,
parsed = '',
remainder = str;
while (mch = rgx.exec(remainder)) { // Not JSLint approved.
parsed += remainder.substring(0, mch.index) + sub[mch[1]];
remainder = remainder.substring(mch.index + mch[0].length);
}
result = (parsed) ? parsed + remainder : str;
但我认为以下代码会更快。它具有更少的变量,更简洁,并使用匿名函数表达式(或 lambda ):
result = str.replace(rgx, function() {
return sub[arguments[1]];
});
This works too,但我的速度错了; in Chrome it's surprisingly (~50%, last time I checked) slower!
...
三个问题:
replace()
循环相比,while()
方法是否有可能更快?如果没有,Code Golf之外的好处是什么?我欢迎任何有关这些流程背后发生的事情的见解。
...
[ Fo(u)r记录:我很高兴在使用'lambda'和/或'functional'这个词时被叫出来。我还在学习这些概念,所以不要以为我确切知道我在说什么,如果我在这里误用这些条款,请随时纠正我。]
答案 0 :(得分:3)
为什么这个过程在Chrome中显得较慢,(例如)在Firefox中速度更快?
因为它必须调用(非本机)函数,这是昂贵的。 Firefox的引擎可能能够通过识别和inlining the lookup来优化它。
与给定较大字符串或数组的while()循环相比,replace()方法是否有可能更快?
是的,它必须减少字符串连接和分配,并且 - 正如您所说 - 初始化的变量较少。然而,你只能测试它来证明我的假设(并且还可以查看http://jsperf.com/match-and-substitute/4的其他片段 - 例如,你可以看到Opera优化了不使用arguments
的lambda-replace2。) p>
如果没有,Code Golf以外有什么好处?
我不认为代码高尔夫是正确的术语。软件质量是关于可读性和可理解性的,在其术语中,功能代码的简洁和优雅(这是主观的)是使用这种方法的原因(实际上我是'我从未见过用exec
,substring
替换并重新连接。
有没有办法优化这个过程,使其更有效率,并且与功能性第二种方法一样无忧无虑?
您不需要remainder
变量。 rgx
有lastIndex
property,会自动通过str
推进匹配。
答案 1 :(得分:2)
while
循环exec()
稍微慢一点,因为你在非全局使用substring
时正在做额外的工作(exec()
)正则表达式。如果需要遍历所有匹配项,则应在全局正则表达式(while
标志启用)上使用g
循环;这样,你就可以避免额外的工作修剪字符串的处理部分。
var rgR = /\((\d+)\)/g;
var mch,
result = '',
lastAppend = 0;
while ((mch = rgR.exec(str)) !== null) {
result += str.substring(lastAppend, mch.index) + sub[mch[1]];
lastAppend = rgR.lastIndex;
}
result += str.substring(lastAppend);
此因素不会影响不同浏览器之间的性能差异。
性能差异似乎来自浏览器的实现。由于对实施的不熟悉,我无法回答差异的来源。
就权力而言,exec()
和replace()
拥有相同的权力。这包括您不使用replace()
返回值的情况。 Example 1。 Example 2
replace()
方法比使用while
的exec()
循环更具可读性(意图更清晰)如果您正在使用函数返回的值(即你在匿名函数中做真正的替换)。您也不必自己重建替换的字符串。这是replace
优于exec()
的地方。 (我希望这能回答问题2的第二部分)。
我认为exec()
用于替换以外的目的(除this之类的特殊情况外)。如果可能,应使用replace()
进行替换。
如果性能在实际输入上严重降低,则只需要优化。我没有任何优化显示,因为已经分析了2个可能的选项,2个不同浏览器之间的性能相矛盾。这可能会在未来发生变化,但就目前而言,您可以选择浏览器中性能最差的一个。