代码之家  ›  专栏  ›  技术社区  ›  pc1oad1etter

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

  •  5
  • pc1oad1etter  · 技术社区  · 17 年前

    我正在努力提高一个函数的性能,该函数接受XML字符串并在返回字符串之前替换某些字符(编码)。函数会受到冲击,因此尽快运行非常重要。通常情况下,所有角色都不存在,因此我想特别针对这一点进行优化。正如您将在示例代码中看到的,要替换的字符串很短,而且相对较少。源字符串通常较短(例如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;
    }
    
    • String.replace 功能会更好吗?
    • 目前我正在替换所有字符,如果单个 角色匹配-可能吗 替换会更好吗?如果是的话,我可能 indexOf 对于此数据集,是否比正则表达式快?
    3 回复  |  直到 17 年前
        1
  •  6
  •   some    17 年前

    我已经对您的原始版本、Ates Gorals哈希、我的改进哈希、使用switch的版本和简单解决方案进行了基准测试。获胜者?简单的解决方案!

    具有匹配数据(由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
    

    (在我的Windows 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,"&");               
    }
    

    首先,检查是否有反斜杠或符号(在所有浏览器中使用indexOf而不是regexp会更快)。如果没有,字符串将原封不动地返回,否则将执行所有替换。在这种情况下,缓存regexp没有多大区别。我尝试使用两个数组,一个使用regexp,另一个使用replacement,但差别不大。

    我通过将散列对象移到外部(因此不会为每次调用内部函数创建并丢弃散列对象),将内部函数移到外部,以便可以重用而不是丢弃散列对象,从而改进了内部函数。

    更新1 错误修正:在“与”测试中移动了一个括号。

    您的一条评论让我相信您自己对字符串进行了编码,如果是这样,我建议您将编码转换为标准编码,这样您就可以使用内置函数。

    使用“%xx”代替“\dd”,其中dd是十进制数,其中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”这样的字符串。

        2
  •  6
  •   Peter Bailey    17 年前

    您可以使用哈希查找:

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

    或者您坚持要扩展原型:

    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)]; }
        }
    );
    

    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 () { ... });
    
        3
  •  2
  •   Peter Bailey    17 年前

    下面是我对重构代码的尝试

    • 使objXMLToString成为静态对象-不需要是可实例化的
    • 去掉了内部init()函数-改为使用数组文字
    • 将for循环转换为while循环(通常更快)
    • 单返回点
    • 范围 变量(现在不再是全局变量)

    这是密码

    var objXMLToString = {
         tester: /\\34|\\39|\\62|\\60|\\13\\10|\\09|\\92|&amp/
        ,replacements: [
             [/\\34/g,'"']
            ,[/\\39/g,"'"]
            ,[/\\62/g,">"]
            ,[/\\60/g,"<"]
            ,[/\\13\\10/g,"\n"]
            ,[/\\09/g,"\t"]
            ,[/\\92/g,"\\"]
            ,[/\&amp;/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;
    }