我正在努力提高一个函数的性能,该函数接受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;
}
String.replace
功能会更好吗? indexOf
可能比此数据集的正则表达式更快吗? 答案 0 :(得分: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 () { ... });
答案 1 :(得分: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”。< / p>
答案 2 :(得分:2)
这是我重构代码的尝试
这是代码
var objXMLToString = {
tester: /\\34|\\39|\\62|\\60|\\13\\10|\\09|\\92|&/
,replacements: [
[/\\34/g,'"']
,[/\\39/g,"'"]
,[/\\62/g,">"]
,[/\\60/g,"<"]
,[/\\13\\10/g,"\n"]
,[/\\09/g,"\t"]
,[/\\92/g,"\\"]
,[/\&/g,"&"]
]
}
String.prototype.XMLToString = function()
{
var newString = this;
if ( objXMLToString.tester.test( this ) )
{
var x = 0, replacer;
while ( replacer = objXMLToString.replacements[x++] )
{
newString = newString.replace( replacer[0], replacer[1] );
}
}
return newString;
}