最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - JS: Replacing all string values in an object that match a pattern? - Stack Overflow

programmeradmin5浏览0评论

I'm looking for an efficient way to replace the values within an object if they match a certain pattern.

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

For instance, i'd like to be able to replace all '###' patterns with a colour for a specific shape:

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

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

Which would allow me quickly to set the stroke and/or fill values of various objects.

Is there a way to do this cleanly? Perhaps using Lodash or regex?

I'm looking for an efficient way to replace the values within an object if they match a certain pattern.

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

For instance, i'd like to be able to replace all '###' patterns with a colour for a specific shape:

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

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

Which would allow me quickly to set the stroke and/or fill values of various objects.

Is there a way to do this cleanly? Perhaps using Lodash or regex?

Share Improve this question edited Nov 2, 2016 at 12:42 Scotty asked Nov 2, 2016 at 12:34 ScottyScotty 2,6756 gold badges30 silver badges39 bronze badges 2
  • what version of lodash are you using? – Meir Commented Nov 2, 2016 at 12:38
  • Using the latest version – Scotty Commented Nov 2, 2016 at 12:41
Add a ment  | 

6 Answers 6

Reset to default 8

Plain JS, no library needed:

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

In lodash, you have a utility function 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;
    }
  });
}

Elaborating on meir answer (getting rid of lodash dependency and circular processing):

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

The JavaScript String.prototype.replace() API should allow you to do exactly that!

You'd have to walk the properties of the object first, but that should be pretty trivial.

This is a version of the code given by Quentin.

  • It doesn't use the cache (so watch out for circles!)
  • It works on any object, e.g. strings, directly.
  • It does whole-string replacement only.
  • It replaces strings found in the keys of an object.
  • It has special cases to leave certain Firebase objects intact, e.g. Timestamp. This is easily extended to include other types of direct-copy
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;
  }
}

You can use _.transform in order to substitute the value of the attribute by the one passed in the object of replacements. In case of the value not being in the replacements, the original value is used.

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/lodash/4.16.6/lodash.min.js"></script>

发布评论

评论列表(0)

  1. 暂无评论