JS:替换匹配模式的对象中的所有字符串值?

时间:2016-11-02 12:34:07

标签: javascript lodash

我正在寻找一种有效的方法来替换对象中的值,如果它们匹配某种模式。

var shapes = {
  square: {
    attr: {
      stroke: '###',
      'stroke-width': '%%%'
    }
  },
  circle: {
    attr: {
      fill: '###',
      'stroke-width': '%%%'
    }
  }
}

例如,我希望能够用特定形状的颜色替换所有'###'图案:

var square = replace(shapes.square, {
  '###': '#333',
  '%%%': 23
});

var circle = replace(shapes.circle, {
  '###': '#111',
  '%%%': 5
});

这将允许我快速设置各种对象的笔触和/或填充值。

有没有办法干净利落地做到这一点?也许使用Lodash或正则表达式?

6 个答案:

答案 0 :(得分:4)

在lodash中,你有一个效用函数mapValues

function replaceStringsInObject(obj, findStr, replaceStr) {
  return _.mapValues(obj, function(value){
    if(_.isString(value)){
      return value.replace(RegEx(findStr, 'gi'), replaceStr);
    } else if(_.isObject(value)){
      return replaceStringInObject(value, findStr, replaceStr);
    } else {
      return value;
    }
  });
}

答案 1 :(得分:2)

普通JS,不需要库:

var shapes = {
  square: {
    attr: {
      stroke: '###',
      'stroke-width': '%%%'
    }
  },
  circle: {
    attr: {
      fill: '###',
      'stroke-width': '%%%'
    }
  }
}
shapes = JSON.parse(
  JSON.stringify(shapes).replace(/###/g,"red").replace(/%%%/g,"23")
)
console.log(shapes);

答案 2 :(得分:0)

JavaScript String.prototype.replace() API应该可以让您做到这一点!

您必须首先遍历对象的属性,但这应该是非常简单的。

答案 3 :(得分:0)

您可以使用_.transform来替换替换对象中传递的属性值。如果值不在替换中,则使用原始值。

function replace(src, repl) {
  return {
    attr: _.transform(src.attr, function(result, val, key) {
      result[key] = repl[val] || val;
    }, {})
  };
}

var shapes = {
  square: {
    attr: {
      stroke: '###',
      'stroke-width': '%%%'
    }
  },
  circle: {
    attr: {
      fill: '###',
      'stroke-width': '%%%'
    }
  }
};

var square = replace(shapes.square, {
  '###': '#333',
  '%%%': 23
});

var circle = replace(shapes.circle, {
  '###': '#111',
  '%%%': 5
});

console.log(square);
console.log(circle);
<script src="https://cdn.jsdelivr.net/lodash/4.16.6/lodash.min.js"></script>

答案 4 :(得分:0)

详细介绍meir answer(摆脱lodash依赖和循环处理):

function replaceStringsInObject(obj, findStr, replaceStr, cache = new Map()) {
    if (cache && cache.has(obj)) return cache.get(obj);

    const result = {};

    cache && cache.set(obj, result);

    for (let [key, value] of Object.entries(obj)) {
        let v = null;

        if(typeof value === 'string'){
            v = value.replace(RegExp(findStr, 'gi'), replaceStr);
        }
        else if (Array.isArray(value)) {
            v = value;
            for (var i = 0; i < value.length; i++) {
                v[i] = replaceStringsInObject(value, findStr, replaceStr, cache);
            }
        }
        else if(typeof value === 'object'){
            v = replaceStringsInObject(value, findStr, replaceStr, cache);
        }
        else {
            v = value;
        }
        result[key] = v;
    }

    return result;
}

答案 5 :(得分:0)

这是 Quentin 给出的代码的一个版本。

  • 它不使用缓存(所以要注意圈子!)
  • 它适用于任何对象,例如字符串,直接。
  • 它只进行全字符串替换。
  • 它替换在对象键中找到的字符串。
  • 保留某些 Firebase 对象完好无损的特殊情况,例如时间戳。这很容易扩展到包括其他类型的直接复制
function replaceStringsInObject(value, findStr, replaceStr) {
  if (typeof value === "string") {
    return findStr === value ? replaceStr : value;
  } else if (value instanceof admin.firestore.Timestamp) {
    return value;
  } else if (value instanceof admin.firestore.GeoPoint) {
    return value;
  } else if (Array.isArray(value)) {
    return value.map((arrayItem) =>
      replaceStringsInObject(arrayItem, findStr, replaceStr)
    );
  } else if (typeof value === "object") {
    const newObj = {};
    for (let [key, oldInnerValue] of Object.entries(value)) {
      const newInnerValue = replaceStringsInObject(
        oldInnerValue,
        findStr,
        replaceStr
      );
      const newKey = key === findStr ? replaceStr : key;
      newObj[newKey] = newInnerValue;
    }
    return newObj;
  } else {
    return value;
  }
}