在JavaScript中合并两个key = value对字符串

时间:2010-08-04 17:47:05

标签: javascript regex arrays

我正试图想出一种有效的方法来覆盖看起来像这样的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];
    }
}

3 个答案:

答案 0 :(得分:7)

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

str3 = str2 + "," + str1;

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

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

如果任何一个字符串可能为空,或者如果允许任何类型的转义,或者如果键只能用字母命名,则需要更加小心。

答案 1 :(得分: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);

修改:忘记将对象转回字符串。

答案 2 :(得分:2)

我想出了以下内容,但我不确定它是否会比你的方法更快,因为还有更多的步骤。还有点长......

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

基准

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

基准测试功能/测试:

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

结果:

Andres(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循环中做了一个boo-boo(length -> arr.length)。我更新了基准测试。这就是我没有测试我的代码所得到的。