-1

I'm looking for a way to replace a given string in a JSON by another string, but only for a certain key. For example, suppose I have the following JSON, data:

[
    {
        "name": "please, I said please",
        "title": "Test One",
        "more": [
            {
                "name": "another name",
                "title": "please write something"
            }
        ]
    },
    {
        "name": "testTwo",
        "title": "Test Two"
    },
    {
        "name": "testThree",
        "title": "Test Three"
    },
    {
        "name": "testFour",
        "title": "Test Four"
    }
]

Let's say for example, I am looking to replace all occurrences of the word "please" by "could you". In this example, I only want to replace whole words. Right now, I've got a working example which does this:

const wordToReplace = "please"

const jsonString = JSON.stringify(data)
const reg = new RegExp(`\\b${wordToReplace}\\b`, 'gi) // whole words only and case insensitive
const dataReplaced = jsonString.replace(reg, function () {
  return 'could you'
}

console.log(JSON.parse(dataReplaced))

Given the above code, the word 'please' will be replaced by 'could you' for all occurrences. However, I want to replace the words only if the key is "title". Right now, it will replace it for any given key (for example, in the first instance where the key is 'name' and also 'title').

One more thing to note is that the JSON can have a varying amount of nested properties as you can see from the example. It's not always the same nested objects within.

Also, the reason I've added a function in the replace method is because I wast trying out ways to specify a key.

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
Adam
  • 2,384
  • 7
  • 29
  • 66
  • I wont recommend using .replace for this. (not my downvote btw) – 0stone0 Jan 20 '22 at 11:03
  • @0stone0 what would you suggest in that case? – Adam Jan 20 '22 at 11:04
  • Or a command line tool like jq, or just fancy looping or reduce – 0stone0 Jan 20 '22 at 11:04
  • How would I loop over the object if the number of nested objects can differ and are not always the same? I've tried doing so recursively but couldn't get that to work. – Adam Jan 20 '22 at 11:11
  • @Adam ... No need to reinvent the wheel. Both `JSON` methods, `parse` and `stringify` are capable each of processing an additionally provided callback referred to as either [`reviver`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#using_the_reviver_parameter) or as [`replacer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#the_replacer_parameter). This callback allows accessing `key` and `value` of the currently processed entry. Thus one can control what kind of `value` is going to be returned. – Peter Seliger Jan 20 '22 at 18:52

2 Answers2

2

No need to reinvent the wheel. Both JSON methods, JSON.parse and JSON.stringify are capable each of processing an additionally provided callback referred to ...

const sampleJSON = '[{"name":"please, I said please","title":"Test One","more":[{"name":"another name","title":"please write something"}]},{"name":"testTwo","title":"Test Two"},{"name":"testThree","title":"Test Three"},{"name":"testFour","title":"Test Four"}]'

const sampleData = JSON.parse(sampleJSON, (key, value) => {
  const regX = (/\bplease\b/gmi);

  return (key === 'title' && regX.test(value))
    ? value.replace(regX, 'could you')
    : value;
});

console.log({ sampleData });
console.log('JSON.parse(sampleJSON) ...', JSON.parse(sampleJSON));
.as-console-wrapper { min-height: 100%!important; top: 0; }

const sampleData = [{
  name: 'please, I said please',
  title: 'Test One',
  more: [{
    name: 'another name',
    title: 'please write something',
  }],
}, {
  name: 'testTwo',
  title: 'Test Two',
}, {
  name: 'testThree',
  title: 'Test Three',
}, {
  name: 'testFour',
  title: 'Test Four',
}];

const sampleJSON = JSON.stringify(sampleData, (key, value) => {
  const regX = (/\bplease\b/gmi);

  return (key === 'title' && regX.test(value))
    ? value.replace(regX, 'could you')
    : value;
});

console.log({ sampleJSON });
console.log("JSON.stringify(sampleData) ...", { stringifed: JSON.stringify(sampleData)});
.as-console-wrapper { min-height: 100%!important; top: 0; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
1

I wont recommend using replace on a json converted to string.

Instead, I'd recursively loop through the array/objects and alter the value if needed

Simple example:

const data = [{"name": "please, I said please", "title": "Test One", "more": [{"name": "another name", "title": "please write something"} ] }, {"name": "testTwo", "title": "Test Two"}, {"name": "testThree", "title": "Test Three"}, {"name": "testFour", "title": "Test Four"} ];
const regx = new RegExp(`\\bplease\\b`, 'gi');

function replace(obj) {
    for (var k in obj) {
        if (typeof obj[k] == "object" && obj[k] !== null) {
            replace(obj[k]);
        } else if (k === 'title') {
            obj[k] = obj[k].replaceAll(regx, 'could you');
        }
    }
    return obj;
}

const result = data.map(o => replace(o));
console.log(result);
0stone0
  • 34,288
  • 4
  • 39
  • 64