替换json / jsObject / string中的多个值

时间:2017-03-30 05:07:32

标签: javascript json regex string replace

我收到了来自网络服务的回复,想要用自定义值替换响应中的某些值。

一种方法是编写树遍历器,然后检查值并替换为我的自定义值

所以响应是这样的:

[
  {
    "name": "n1",
    "value": "v1",
    "children": [
      {
        "name": "n2",
        "value": "v2"
      }
    ]
  },
  {
    "name": "n3",
    "value": "v3"
  }
]

现在我的自定义地图就像这样

const map = {
  "v1": "v11",
  "v2": "v22",
  "v3": "v33"
};

我想要的只是

[
  {
    "name": "n1",
    "value": "v11",
    "children": [
      {
        "name": "n2",
        "value": "v22"
      }
    ]
  },
  {
    "name": "n3",
    "value": "v33"
  }
]

我在想是否可以对我的响应进行字符串化,然后使用我的值映射中的自定义构建正则表达式替换值。

  1. 与树遍历相比,它会更快吗?
  2. 如果是,我应该怎么做?
  3. 有点像这样

      

    originalString.replace(regexp,function(replacement))

3 个答案:

答案 0 :(得分:3)

树遍历 更快

请注意,在正则表达式实现中可以更有效地完成某些操作,但我仍然认为还有一些瓶颈需要解释。

为什么正则表达式很慢:

为什么正则表达式较慢可能还有很多原因,但我会解释至少一个重要原因:

当您使用正则表达式进行查找和替换时,您每次都会使用创建新字符串并每次都执行匹配。正则表达式can be very expensive和我的实现并不特别便宜。

为什么树遍历更快:

在树遍历中,我直接改变对象。这并不需要创建新的string对象或任何新对象。我们每次也都没有对整个字符串执行完整搜索。

<强>结果

运行下面的性能测试。使用console.time进行测试以记录所需的时间。看树遍历要快得多。

&#13;
&#13;
function usingRegex(obj, map) {
  return JSON.parse(Object.keys(map).map(oldValue => ({
    oldValue,
    newValue: map[oldValue]
  })).reduce((json, {
    oldValue,
    newValue
  }) => {
    return json.replace(
      new RegExp(`"value":"(${oldValue})"`),
      () => `"value":"${newValue}"`
    );
  }, JSON.stringify(obj)));
}

function usingTree(obj, map) {
  function traverse(children) {
    for (let item of children) {
      if (item && item.value) {
        // get a value from a JS object is O(1)!
        item.value = map[item.value];
      }
      if (item && item.children) {
        traverse(item.children)
      }
    }
  }
  
  traverse(obj);
  return obj; // mutates
}

const obj = JSON.parse(`[
  {
    "name": "n1",
    "value": "v1",
    "children": [
      {
        "name": "n2",
        "value": "v2"
      }
    ]
  },
  {
    "name": "n3",
    "value": "v3"
  }
]`);

const map = {
  "v1": "v11",
  "v2": "v22",
  "v3": "v33"
};

// show that each function is working first
console.log('== TEST THE FUNCTIONS ==');
console.log('usingRegex', usingRegex(obj, map));
console.log('usingTree', usingTree(obj, map));

const iterations = 10000; // ten thousand
console.log('== DO 10000 ITERATIONS ==');
console.time('regex implementation');
for (let i = 0; i < iterations; i += 1) {
  usingRegex(obj, map);
}
console.timeEnd('regex implementation');

console.time('tree implementation');
for (let i = 0; i < iterations; i += 1) {
  usingTree(obj, map);
}
console.timeEnd('tree implementation');
&#13;
&#13;
&#13;

答案 1 :(得分:1)

  

与树遍历相比,它会更快吗?

我不知道。我认为这取决于输入的大小和替换地图的大小。您可以在JSPerf.com处运行一些测试。

  

如果是,我应该怎么做?

如果要替换的值不需要任何特殊的转义或其他什么,那么使用基于正则表达式的字符串替换相当容易。像这样:

const input = [
  {
    "name": "n1",
    "value": "v1",
    "children": [
      {
        "name": "n2",
        "value": "v2"
      }
    ]
  },
  {
    "name": "n3",
    "value": "v3"
  }
];

const map = {
  "v1": "v11",
  "v2": "v22",
  "v3": "v33"
};

// create a regex that matches any of the map keys, adding ':' and quotes
// to be sure to match whole property values and not property names
const regex = new RegExp(':\\s*"(' + Object.keys(map).join('|') + ')"', 'g');

// NOTE: if you've received this data as JSON then do the replacement
// *before* parsing it, don't parse it then restringify it then reparse it.
const json = JSON.stringify(input);
const result = JSON.parse(
  json.replace(regex, function(m, key) { return ': "' + map[key] + '"'; })
);

console.log(result);

答案 2 :(得分:0)

绝对遍历变得更快,因为字符串替换意味着对最终字符串中的每个字符进行移动,而不是迭代器可以跳过不一定的项目。