我正在努力提高一个函数的性能,该函数接受XML字符串并在返回字符串之前替换某些字符(编码).该函数受到攻击,因此尽可能快地运行非常重要.USUAL案例是没有任何字符存在 - 所以我想特别优化它.正如您将在示例代码中看到的那样,要替换的字符串很短,而且相对较少.源字符串通常很短(例如10-20个字符)但可能更长(例如200个字符左右).
到目前为止,我已经确保正则数据库是预编译的,并且我已经消除了嵌套函数,这会降低操作速度(此时部分毫秒很重要.)
var objXMLToString = new XMLToStringClass(); function XMLToStringClass(){ this.tester= /\\34|\\39|\\62|\\60|\\13\\10|\\09|\\92|&/; this.replacements=[]; var self=this; function init(){ var re = new regexReplacePair(/\\34/g,'"'); self.replacements.push(re); re = new regexReplacePair(/\\39/g,"'"); self.replacements.push(re); re = new regexReplacePair(/\\62/g,">"); self.replacements.push(re); re = new regexReplacePair(/\\60/g,"<"); self.replacements.push(re); re = new regexReplacePair(/\\13\\10/g,"\n"); self.replacements.push(re); re = new regexReplacePair(/\\09/g,"\t"); self.replacements.push(re); re = new regexReplacePair(/\\92/g,"\\"); self.replacements.push(re); re = new regexReplacePair(/\&/g,"&"); self.replacements.push(re); } init(); } function regexReplacePair(regex,replacementString){ this.regex = regex; this.replacement = replacementString; } String.prototype.XMLToString = function() { newString=this; if(objXMLToString.tester.test(this)){ for (var x = 0;x
是否有可能在这种情况下
String.replace
功能会更好?目前我正在替换所有字符,如果单个字符匹配 - 是否有可能测试然后有条件地替换会更好?如果是这样,可能
indexOf
比这个数据集的正则表达式更快?
Ates Goral.. 6
您可以使用哈希查找:
str.replace( /(\\34|\\39|\\62|\\60|\\13\\10|\\09|\\92|&)/g, function () { return { "\\34": "\"", "\\39": "'", //... "&": "&" }[arguments(1)]; } );或者你坚持扩展原型:
var hash = { "\\34": "\"", "\\39": "'", //... "&": "&" }; String.prototype.XMLToString = function () { return this.replace( /(\\34|\\39|\\62|\\60|\\13\\10|\\09|\\92|&)/g, function () { return hash[arguments(1)]; } } );这可能更快(需要基准测试):
String.prototype.XMLToString = function () { var s = this; for (var r in hash) { s = s.split(r).join(hash[r]); } return s; );
更新
您可以从哈希生成正则表达式:
var arr = []; for (var r in hash) { arr.push(r); } var re = new RegExp("(" + arr.join("|") + ")", "g");然后将其用作:
s = s.replace(re, function () { ... });
some.. 6
我已经对您的原始版本,Ates Gorals哈希,我改进的哈希,使用开关的版本以及简单的解决方案进行了基准测试.获胜者,冠军?简单的解决方案!
使用匹配数据(85个字符串)
original simple hash switch ag-hash FF3 194 188 250 240 424 IE7 188 172 641 906 2203 Chrome1 161 156 165 165 225 Opera9 640 625 531 515 734使用非匹配数据(85个字符串):
original simple hash switch ag-hash FF3 39 4 34 34 39 IE7 125 15 125 125 156 Chrome1 45 2 54 54 57 Opera9 156 15 156 156 156(在我的窗口xp笔记本电脑上测试,1.7GHz,ymmv)
简单的解决方案:
function XMLToString(str) { return (str.indexOf("\\")<0 && str.indexOf("&")<0) ? str : str .replace(/\\34/g,'"') .replace(/\\39/g,"'") .replace(/\\62/g,">") .replace(/\\60/g,"<") .replace(/\\13\\10/g,"\n") .replace(/\\09/g,"\t") .replace(/\\92/g,"\\") .replace(/\&/g,"&"); }说明:
首先检查是否有反斜杠或符号(在所有浏览器中使用indexOf而不是正则表达式更快).如果没有,则返回未触及的字符串,否则执行所有替换.在这种情况下,缓存regexp并不会产生差异.我尝试了两个阵列,一个带有正则表达式,一个带有替换,但它没有太大的区别.
在原始版本中,您可以测试所有组合,以检测是否应该进行替换.这是昂贵的,因为正则表达式引擎必须将每个位置与每个组合进行比较.我简化了它.
我通过将哈希对象移动到外部来改进Ates Gorals(因此它不会被创建并在每次调用内部函数时被抛弃),将内部函数移到外部以便可以重用而不是丢弃.
更新1修正:在&符号测试中移动了一个括号.
更新2
您的一条评论让我相信您自己编码字符串,如果是这种情况,我建议您将编码切换为标准编码,这样您就可以使用内置函数.
而不是"\ dd",其中dd是十进制数,请使用"%xx",其中xx是十六进制数.然后你可以使用更快速的内置decodeURIComponent,作为奖励可以解码任何字符,包括unicode.
matching non match FF3 44 3 IE7 93 16 Chrome1 132 1 Opera9 109 16.
function XMLToString_S1(str) { return (str.indexOf("%")<0) ? str : decodeURIComponent(str).replace(/\x0D\x0A/g,"\n") }所以不要像"\ 09test\60\34string\34\62\13\10 \"这样的字符串,而是有一个字符串,如"%09test%3c%22string%22%3e%0d%0a".
1> Ates Goral..:您可以使用哈希查找:
str.replace( /(\\34|\\39|\\62|\\60|\\13\\10|\\09|\\92|&)/g, function () { return { "\\34": "\"", "\\39": "'", //... "&": "&" }[arguments(1)]; } );或者你坚持扩展原型:
var hash = { "\\34": "\"", "\\39": "'", //... "&": "&" }; String.prototype.XMLToString = function () { return this.replace( /(\\34|\\39|\\62|\\60|\\13\\10|\\09|\\92|&)/g, function () { return hash[arguments(1)]; } } );这可能更快(需要基准测试):
String.prototype.XMLToString = function () { var s = this; for (var r in hash) { s = s.split(r).join(hash[r]); } return s; );
更新
您可以从哈希生成正则表达式:
var arr = []; for (var r in hash) { arr.push(r); } var re = new RegExp("(" + arr.join("|") + ")", "g");然后将其用作:
s = s.replace(re, function () { ... });
2> some..:我已经对您的原始版本,Ates Gorals哈希,我改进的哈希,使用开关的版本以及简单的解决方案进行了基准测试.获胜者,冠军?简单的解决方案!
使用匹配数据(85个字符串)
original simple hash switch ag-hash FF3 194 188 250 240 424 IE7 188 172 641 906 2203 Chrome1 161 156 165 165 225 Opera9 640 625 531 515 734使用非匹配数据(85个字符串):
original simple hash switch ag-hash FF3 39 4 34 34 39 IE7 125 15 125 125 156 Chrome1 45 2 54 54 57 Opera9 156 15 156 156 156(在我的窗口xp笔记本电脑上测试,1.7GHz,ymmv)
简单的解决方案:
function XMLToString(str) { return (str.indexOf("\\")<0 && str.indexOf("&")<0) ? str : str .replace(/\\34/g,'"') .replace(/\\39/g,"'") .replace(/\\62/g,">") .replace(/\\60/g,"<") .replace(/\\13\\10/g,"\n") .replace(/\\09/g,"\t") .replace(/\\92/g,"\\") .replace(/\&/g,"&"); }说明:
首先检查是否有反斜杠或符号(在所有浏览器中使用indexOf而不是正则表达式更快).如果没有,则返回未触及的字符串,否则执行所有替换.在这种情况下,缓存regexp并不会产生差异.我尝试了两个阵列,一个带有正则表达式,一个带有替换,但它没有太大的区别.
在原始版本中,您可以测试所有组合,以检测是否应该进行替换.这是昂贵的,因为正则表达式引擎必须将每个位置与每个组合进行比较.我简化了它.
我通过将哈希对象移动到外部来改进Ates Gorals(因此它不会被创建并在每次调用内部函数时被抛弃),将内部函数移到外部以便可以重用而不是丢弃.
更新1修正:在&符号测试中移动了一个括号.
更新2
您的一条评论让我相信您自己编码字符串,如果是这种情况,我建议您将编码切换为标准编码,这样您就可以使用内置函数.
而不是"\ dd",其中dd是十进制数,请使用"%xx",其中xx是十六进制数.然后你可以使用更快速的内置decodeURIComponent,作为奖励可以解码任何字符,包括unicode.
matching non match FF3 44 3 IE7 93 16 Chrome1 132 1 Opera9 109 16.
function XMLToString_S1(str) { return (str.indexOf("%")<0) ? str : decodeURIComponent(str).replace(/\x0D\x0A/g,"\n") }所以不要像"\ 09test\60\34string\34\62\13\10 \"这样的字符串,而是有一个字符串,如"%09test%3c%22string%22%3e%0d%0a".