在JavaScript中替换字符串中的一系列字符的最佳方法是什么

pc1*_*ter 5 javascript regex

我正在努力提高一个函数的性能,该函数接受XML字符串并在返回字符串之前替换某些字符(编码).该函数受到攻击,因此尽可能快地运行非常重要.USUAL案例是没有任何字符存在 - 所以我想特别优化它.正如您将在示例代码中看到的那样,要替换的字符串很短,而且相对较少.源字符串通常很短(例如10-20个字符)但可能更长(例如200个字符左右).

到目前为止,我已经确保正则数据库是预编译的,并且我已经消除了嵌套函数,这会降低操作速度(此时部分毫秒很重要.)

var objXMLToString = new XMLToStringClass();
function XMLToStringClass(){
    this.tester= /\\34|\\39|\\62|\\60|\\13\\10|\\09|\\92|&amp/;
    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(/\&amp;/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比这个数据集的正则表达式更快?

Ate*_*ral 6

您可以使用哈希查找:

str.replace(
    /(\\34|\\39|\\62|\\60|\\13\\10|\\09|\\92|&amp)/g,
    function () {
        return {
            "\\34": "\"",
            "\\39": "'",
            //...
            "&amp": "&"
        }[arguments(1)];
    }
);
Run Code Online (Sandbox Code Playgroud)

或者你坚持扩展原型:

var hash = {
    "\\34": "\"",
    "\\39": "'",
    //...
    "&amp": "&"
};

String.prototype.XMLToString = function () {
    return this.replace(
        /(\\34|\\39|\\62|\\60|\\13\\10|\\09|\\92|&amp)/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)


som*_*ome 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
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(/\&amp;/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".