【问题标题】:Creation of object with key/value pairs in a string?使用字符串中的键/值对创建对象?
【发布时间】:2018-08-06 05:54:18
【问题描述】:

我有以下字符串:

person:juan&age:24&knowledge:html

问题是有时字符串是:

knowledge:html&person:juan&age:24

它可以改变键和值的位置。

在这种情况下,我会这样写:

const keys = ["person", "age", "knowledge"];
const keyAndValues = "person:juan&age:24&knowledge:html";

const result = [];

keys.forEach(key => {
  const indexKeyValues = keyAndValues.indexOf(key);
  if (indexKeyValues !== -1) {
    const lastCharIndex = keyAndValues.substring(indexKeyValues).indexOf("&");
    return keyAndValues.substring(indexKeyValues + key.length, lastCharIndex === -1 ? keyAndValues.substring(indexKeyValues).length - 1 || lastCharIndex);
  }
});

但我不喜欢它,如果我能做这样的事情会很棒:

const resultsExpected = /regexGroupedRegardlessOfPosition/g.match("person:juan&age:24&knowledge:html");

console.log(resultsExpected); // { person: "juan", age: 24, knowledge: "html" }

【问题讨论】:

  • 我不认为正则表达式在这种情况下是最好的解决方案。老实说,我什至不认为它适用于这个问题的任何解决方案。
  • 为什么可能有办法在:和链的开头之间抓取东西,看它是否属于某个键,然后抓取值
  • 我认为如果它有效,你应该使用你所拥有的。它简单易读,老实说,正则表达式很少。
  • 看起来你最好在&上拆分字符串,然后在:上拆分每个结果
  • 听起来很合理@MattBurland,这也会使其更具可读性

标签: javascript arrays regex string object


【解决方案1】:

作为Phiter said,我认为正则表达式在这里对你没有帮助。您可能知道这个老笑话:“我有一个问题。我知道!我将使用正则表达式!哦,现在我有两个问题。”

我会在& 上拆分字符串,然后在: 上拆分每个子字符串,然后填写其中的值:

function strToObject(str) {
  var rv = {};
  str.split("&").forEach(function(substr) {
    var index = substr.indexOf(":");
    if (index === -1) {
      rv[substr] = undefined;
    } else {
      rv[substr.substring(0, index)] = substr.substring(index+1);
    }
  });
  return rv;
}

现场示例:

function strToObject(str) {
  var rv = {};
  str.split("&").forEach(function(substr) {
    var index = substr.indexOf(":");
    if (index === -1) {
      rv[substr] = undefined;
    } else {
      rv[substr.substring(0, index)] = substr.substring(index+1);
    }
  });
  return rv;
}

console.log(strToObject("person:juan&age:24&knowledge:html"));
console.log(strToObject("knowledge:html&person:juan&age:24"));
.as-console-wrapper {
  max-height: 100% !important;
}

这可以通过以下方式变得更简洁:

  • 使用 ES2015+ 语法。
  • 通过创建不必要的临时对象(不过,JavaScript 引擎可以快速创建和销毁对象,因此为简洁性付出代价是值得的)
  • 假设值从不包含: 字符。我使用indexOf 而不是更简单的split 来分隔名称和值,以允许值包含: 的可能性(例如,foo:blah:blah&bar:blah 其中foo"blah:blah") - 许多如果不是大多数其他解决方案在这种情况下会丢弃部分价值

【讨论】:

    【解决方案2】:
    (knowledge|person|age):([^&]+)
    

    您可能不想,但接受任何密钥:

    (\w+):([^&]+)
    

    https://regex101.com/r/HwW5I1/1/

    【讨论】:

      【解决方案3】:

      我认为将这种类型的字符串转换为对象的简单函数可能是更好的解决方案。看看这个:

      var keyAndValues = "person:juan&age:24&knowledge:html";
      
      function weirdStringToObject(str){
          var obj = {};
          str.split('&').forEach(function(substr){
              var kv = substr.split(':');
              var key = kv[0];
              var value = kv[1] || null;
              obj[key] = value;
          });
          return obj;
      }
      
      console.log(weirdStringToObject(keyAndValues));

      这需要一些额外的验证,但从这里很容易理解。

      【讨论】:

      • 我在第一个实现中使用了map,但这很愚蠢。在我开始写作之后,我注意到不可能将 key:value.map 配对返回。
      【解决方案4】:

      您可以使用:

      工作示例:

      const str = "person:juan&age:24&knowledge:html";
      
      let result = str.split("&").reduce((r, s) => {
        let i = s.indexOf(':');
        r[s.slice(0, i)] = s.slice(i + 1);
        return r;
      }, {});
      
      console.log(result);

      【讨论】:

        【解决方案5】:

        您可以拆分字符串,然后拆分部分并获取对象的键/值。

        function getValues(string) {
            var object = {};
            
            string && string.split('&').forEach(p => {
                var [key, ...value] = p.split(':');
                object[key] = value.join(':');
            });
            return object;
        }
        
        console.log(getValues("knowledge:html&person:juan&age:24"));
        console.log(getValues("foo:bar:baz&cool:space:aliens:survive"));
        console.log(getValues(""));

        【讨论】:

        • 这是 ES6 语法,对吧?您创建var [key, value]的部分?
        • @Phiter,对,是destructuring assignment
        • 使用split 作为: 部分假定该值永远不会包含:,当然。
        • @T.J.Crowder,在这种情况下需要转义。
        • @NinaScholz:不,不需要转义。条目之间的分隔符是&。看我的回答。
        【解决方案6】:

        这是获取对象的单个表达式:

        const keyAndValues = "person:juan&age:24&knowledge:html";
        
        const obj = Object.assign(...keyAndValues.split('&').map(s => s.split(':'))
                                                 .map(([k, v]) => ({ [k]: v }))
        );
        
        console.log(obj);

        这使用 ES6 destructuring assignmentspread syntaxcomputed property names

        【讨论】:

        • 如果我们只定义一个“地图”而不是 2 个,是否会减少迭代次数?
        • 非常简洁,但是@juangarcia:请注意,将split 用于: 部分假定该值将永远不会包含:,当然。 (这也会为每个条目创建一个一次性对象,但 JavaScript 引擎在创建和丢弃对象方面速度很快。)
        • @juangarcia,你可以用一个map 来做到这一点,但是你需要将split 的结果存储在变量中,然后从这些变量中返回合成对象:事实并非如此像两个map 电话一样优雅,每个电话都有自己的表情。确实,您有一个额外的迭代,但它也用于解构赋值的目的,并且不会影响整体时间复杂度。
        猜你喜欢
        • 2015-09-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-23
        • 2013-03-25
        • 1970-01-01
        相关资源
        最近更新 更多