【问题标题】:Merging two strings of key=value pairs in JavaScript在 JavaScript 中合并两个键=值对字符串
【发布时间】:2011-03-25 09:47:17
【问题描述】:

我正在尝试想出一种有效的方法来覆盖 2 个如下所示的字符串:

str1 = "width=800,height=600,resizable=no,titlebar=no";
str2 = "width=100,height=100";

在上面的例子中,str2 应该覆盖str1 以产生str3

str3 = "width=100,height=100,resizable=no,titlebar=no";

在我的测试中,我将str2 变成了一个数组,并针对str1 中的匹配项测试了每个键。

谁能想到一个更有效的方法来写这个:

str1 = "width=800,height=600,resizable=no,titlebar=no";
str2 = "width=100,height=100";
sArray = str2.split(",");

for( var i = 0; i < sArray.length; i++ ) {
    var key = sArray[i].match(/(\w+)=/gi).toString().replace("=", ""),
        in_str1 = str1.search(key),
        replace_pattern = new RegExp(key+"=(\\w+)", "gi");

    if(in_str1 !== -1){                 
        str1 = str1.replace(replace_pattern, sArray[i]);
    } else {
        str1 = str1 + "," + sArray[i];
    }
}

【问题讨论】:

标签: javascript regex arrays


【解决方案1】:

这是一个非常简洁的基于正则表达式的解决方案:

str3 = str2 + "," + str1;

while ((temp = str3.replace(/\b([a-z]+)(=.*)\b\1=[^,]*,?/, "$1$2")) != str3) {
    str3 = temp;
}

它的工作原理是将覆盖字符串添加到可覆盖字符串之前,然后反复删除连接字符串中稍后出现的重复项,直到没有。

如果任何一个字符串可能为空,或者允许任何类型的转义,或者键可以命名而不是仅使用字母,则需要多加注意。

【讨论】:

  • 谢谢肖恩。这是我所设想的。正则表达式的概念很有趣,但它更有效吗?
  • @Andres:我怀疑可能是这样,但如果不对其进行基准测试,我无法确定。除非这是您要执行数千次的操作,否则除了效率极低的方法之外的任何方法都应该没问题。
  • @Andres:我添加了一些基准测试,但我必须同意 Sean 的观点,即这里的几毫秒和那里不会有什么不同。虽然我个人会尽量避免这种特殊的解决方案,因为我很擅长正则表达式,如果遇到它,我将很难维护它。
  • 我要做的唯一改变是用逗号/\b([a-z]+)(=.*),\1=[^,]*,?/替换\1之前的单词边界\b
  • 看起来,在这种情况下,最简洁的解决方案也是最快的解决方案。
【解决方案2】:

没有尝试运行它,但这应该可以工作,创建了一个实用函数parseParamString,它接受该格式的字符串,以及一个可选的对象来添加键值对。

function parseParamString(str, obj) {
    var pairs = str.split(","),
        i = 0, l = pairs.length,
        pair;
    obj || (obj = {});
    for (; l > i; ++i) {
        pair = pairs[i].split("=", 2);
        obj[pair[0]] = pair[1];
    }
    return obj;
}

function buildParamString(obj) {
    var pairs = [], i;
    for (i in obj) {
        if (obj.hasOwnProperty(i)) {
            pairs.push(i + "=" + obj[i]);
        }
    }
    return pairs.join(",");
}

var str1 = "width=800,height=600,resizable=no,titlebar=no",
    str2 = "width=100,height=100";

var resultObj = parseParamString(str2, parseParamString(str1));

var resultSTr = buildParamString(resultObj);

编辑:忘记将对象转回字符串。

【讨论】:

  • 谢谢瑞恩。你觉得我的方法和你的怎么样?
  • 这不是一个糟糕的解决方案,它肯定比丹尼尔和我的方法更简洁。但是,如果没有向我解释您方法的目的,我将很难弄清楚。肖恩极其简洁的正则表达式方法也是如此,但同时也有一定的美感。另外,我通常反对动态正则表达式。它们本质上没有任何问题,只是个人喜好。
【解决方案3】:

我想出了以下方法,但我不确定它是否会比您的方法更快,因为涉及更多步骤。还有就是有点长……

var toObj = function (str) {
   var arr = str.split(","), obj = {};
   for (var i = 0; i < arr.length; i++) {
      var keyval = arr[i].split("=", 2);
      obj[keyval[0]] = keyval[1];
   }
   return obj;
};

var objToString = function (obj) {
   var stringBuilder = [];
   for (var k in obj) {
      stringBuilder.push(k+"="+obj[k]);
   }
   return stringBuilder.join(",");
};

var merge  = function (obj1, obj2) { // merge obj1 into obj2.. obj2 will be modified.
   for (var k in obj1) {
      obj2[k] = obj2[k] || obj1[k];
   }
   return obj2;
};

var newStr = objToString(merge(toObj(str1), toObj(str2));

基准测试

我很无聊,所以我决定对所提供的这 3 种不同解决方案进行快速基准测试。

基准函数/测试:

function benchmark(name, fn, n) { 
   console.time(name); 
   for(var i = 0; i < n; i++) 
      fn(); 
   console.timeEnd(name);  
}

结果:

安德烈斯(OP):

benchmark("Andres", function () { paramStrAndres("width=800,height=600,resizable=no,titlebar=no", "width=100,height=100"); }, 10000);
Andres: 505ms

瑞安/RWT:

benchmark("RWT", function () { paramStrRWT("width=800,height=600,resizable=no,titlebar=no", "width=100,height=100"); }, 10000);
RWT: 86ms

丹尼尔:

benchmark("Daniel", function () { paramStrDaniel("width=800,height=600,resizable=no,titlebar=no", "width=100,height=100"); }, 10000);
Daniel: 98ms

肖恩:

benchmark("Sean", function () { paramStrSean("width=800,height=600,resizable=no,titlebar=no", "width=100,height=100"); }, 10000);
Sean: 40ms

测试的功能:

安德烈斯:

function paramStrAndres(str1, str2) {
    sArray = str2.split(",");

    for( var i = 0; i < sArray.length; i++ ) {
        var key = sArray[i].match(/(\w+)=/gi).toString().replace("=", ""),
        in_str1 = str1.search(key),
        replace_pattern = new RegExp(key+"=(\\w+)", "gi");

        if(in_str1 !== -1){                 
            str1 = str1.replace(replace_pattern, sArray[i]);
        } else {
            str1 = str1 + "," + sArray[i];
        }
    }
    return str1;
}

瑞安/RWT:

function paramStrRWT (str1, str2) {
 function parseParamString(str, obj) {
    var pairs = str.split(","),
        i = 0, l = pairs.length,
        pair;
    obj || (obj = {});
    for (; l > i; ++i) {
        pair = pairs[i].split("=", 2);
        obj[pair[0]] = pair[1];
    }
    return obj;
 }

 function buildParamString(obj) {
    var pairs = [], i;
    for (i in obj) {
        if (obj.hasOwnProperty(i)) {
            pairs.push(i + "=" + obj[i]);
        }
    }
    return pairs.join(",");
 }
 var resultObj = parseParamString(str2, parseParamString(str1));
 return buildParamString(resultObj);
}

我的:

function paramStrDaniel(str1, str2) {
    var toObj = function (str) {
        var arr = str.split(","), obj = {};
        for (var i = 0; i < arr.length; i++) {
            var keyval = arr[i].split("=", 2);
            obj[keyval[0]] = keyval[1];
        }
        return obj;
    };

    var objToString = function (obj) {
        var stringBuilder = [];
        for (var k in obj) {
            stringBuilder.push(k+"="+obj[k]);
        }
        return stringBuilder.join(",");
    };

    var merge  = function (obj1, obj2) { // merge obj1 into obj2.. obj2 will be modified.
        for (var k in obj1) {
            obj2[k] = obj2[k] || obj1[k];
        }
        return obj2;
    };

    return objToString(merge(toObj(str1), toObj(str2)));
    }

肖恩:

function paramStrSean(str1, str2) {
    var str3 = str2 + "," + str1, temp;

    while ((temp = str3.replace(/\b([a-z]+)(=.*)\b\1=[^,]*,?/, "$1$2")) != str3) {
        str3 = temp;
    }
    return str3;
    }

编辑:我觉得奇怪的是我的版本比 Ryan 的版本快,因为它们是相似的。在查看之后,我看到我在 for 循环 (length -&gt; arr.length) 上做了一个嘘声。我已经更新了基准。这就是我没有测试我的代码的结果。

【讨论】:

  • 感谢基准测试!我很高兴你的方法和我的方法所需的时间是如此不同。我知道.hasOwnProperty()(我们的解决方案之间唯一明显的区别)很贵,但我不知道它这么贵!
  • @Ryan W Tenney:实际上,你的快了大约 10 毫秒!我在代码中犯了一个错误,导致 for 循环什么都不做。我已经更新了帖子。
猜你喜欢
  • 1970-01-01
  • 2018-02-14
  • 2019-06-29
  • 2022-12-08
  • 2018-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-13
相关资源
最近更新 更多