skip to Main Content

I have a JSON coming from back end to front, that uses single quotes everywhere (I can’t change the generator, because Magento 2 widget I use is braking if double quotes are passed). It looks like this:

{ 'mood': 'happy', 'reason': 'why shouldn't I?'}

I need to change the single quotes to double, without actually touching the apostrophes in the middle. I think the best way to do this would be to use a regular expression to match all JSON-related single quotes and replace them to double, without touching the apostrophes inside.

There are plenty of questions like this one on SO, but I haven’t been able to find a solution that actually works for me for the last 1.5 hours. The closest solution so far was this:

goodJson = brokenJson.replace(/(?<=[{,:] )'|'(?=[:,]| })/g, '"');

It should match all single quotes that are either preceded by {, ,, , and :, or followed by those characters. However, in my output I get this:

{ "mood": "happy", "reason": "why'd not'}

So, the final quote is not being replaced despite standing next to the closing curly brace.

Can you tell me why doesn’t it work, and what would be the best way to achieve desired outcome?

2

Answers


  1. Although your character string does not represent a JSON format, your regex was not far from the correct result:

    const goodJson = brokenJson => brokenJson.replace(/(?<=[{,: ])'|'(?=[:, }])/g, '"');
    
    console.log(goodJson("{ 'mood': 'happy', 'reason': 'why'd not' }")); // { "mood": "happy", "reason": "why'd not" }
    console.log(goodJson("{'mood': 'happy', 'reason': 'why'd not'}")); // {"mood": "happy", "reason": "why'd not"}

    Good luck !

    Login or Signup to reply.
  2. As others mentioned, this is not JSON, best to have this fixed upstream. If you want to fix broken JSON to a flaky JSON, and the value is always a string, you can try this:

    function brokenToFlakyJson(str) {
     return str.replace(/'(w+)' *: *'(.*?)'(?=[,| *}])/g, '"$1": "$2"');
    }
    
    [
      "{ 'mood': 'happy', 'reason': 'why shouldn't I?'}",
      "{ 'mood': 'happy 'cat'', 'reason': 'why shouldn't I?'}",
      "{ 'mood': 'happy', 'reason': 'why shouldn't', 'I?'}",
    ].forEach(str => {
      console.log('broken: ' + str + 'n flaky: ' + brokenToFlakyJson(str));
    })  

    Output:

    broken: { 'mood': 'happy', 'reason': 'why shouldn't I?'}
     flaky: { "mood": "happy", "reason": "why shouldn't I?"}
    broken: { 'mood': 'happy 'cat'', 'reason': 'why shouldn't I?'}
     flaky: { "mood": "happy 'cat'", "reason": "why shouldn't I?"}
    broken: { 'mood': 'happy', 'reason': 'why shouldn't', 'I?'}
     flaky: { "mood": "happy", "reason": "why shouldn't", 'I?'}
    

    As you can see from the output, the 3rd string is not handled properly. We can add another safeguard, but that one will break too, etc.

    Explanation of regex:

    • '(w+)' — expect key enclosed in single quotes
    • *: * — expect colon separator with optional spaces
    • '(.*?)' — expect value enclosed in single quotes, non-greedy scan
    • (?=[,| *}]) — positive lookahead, expecting a comma or end of object
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search