我正在努力提高一个函数的性能,该函数接受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<objXMLToString.replacements.length;x++){
newString=newString.replace(objXMLToString.replacements[x].regex,objXMLToString.replacements[x].replacement);
}
return newString;
}
return this;
}
Run Code Online (Sandbox Code Playgroud)
String.replace功能会更好?indexOf比这个数据集的正则表达式更快? 您可以使用哈希查找:
str.replace(
/(\\34|\\39|\\62|\\60|\\13\\10|\\09|\\92|&)/g,
function () {
return {
"\\34": "\"",
"\\39": "'",
//...
"&": "&"
}[arguments(1)];
}
);
Run Code Online (Sandbox Code Playgroud)
或者你坚持扩展原型:
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)]; }
}
);
Run Code Online (Sandbox Code Playgroud)
这可能更快(需要基准测试):
String.prototype.XMLToString = function () {
var s = this;
for (var r in hash) {
s = s.split(r).join(hash[r]);
}
return s;
);
Run Code Online (Sandbox Code Playgroud)
您可以从哈希生成正则表达式:
var arr = [];
for (var r in hash) {
arr.push(r);
}
var re = new RegExp("(" + arr.join("|") + ")", "g");
Run Code Online (Sandbox Code Playgroud)
然后将其用作:
s = s.replace(re, function () { ... });
Run Code Online (Sandbox Code Playgroud)
我已经对您的原始版本,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
Run Code Online (Sandbox Code Playgroud)
使用非匹配数据(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
Run Code Online (Sandbox Code Playgroud)
(在我的窗口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,"&");
}
Run Code Online (Sandbox Code Playgroud)
说明:
首先检查是否有反斜杠或符号(在所有浏览器中使用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
Run Code Online (Sandbox Code Playgroud)
.
function XMLToString_S1(str) {
return (str.indexOf("%")<0) ? str : decodeURIComponent(str).replace(/\x0D\x0A/g,"\n")
}
Run Code Online (Sandbox Code Playgroud)
所以不要像"\ 09test\60\34string\34\62\13\10 \"这样的字符串,而是有一个字符串,如"%09test%3c%22string%22%3e%0d%0a".