Problem with escape characters in JSON

I have a large json file (that verifies as good when I checked). But when I try to access the string with JSON.parse() it gives me an error because of the “\r” escaped character in it. I have read everywhere that this is the way to include special characters and the json string verifies as ok. If I remove the \r from the example below it runs, with the \r included it fails.

<script>
var txt = '{"name":"\rJohn", "age":30}'
var obj = JSON.parse(txt);
alert(obj.name + ", " + obj.age);
</script>

double the slash.

Thanks for the quick reply!
The txt variable is actually the result of a fetch from another url and is about 50k in size. Can’t edit it manually. Also, I can’t figure out how to fix it programmatically. I’ve tried
txt = txt.replaceAll("\" , "\\")
which did not work even with variations in the number of \ characters I used. I don’t know why the parse method has such an issue with this. The source of the json looks ok when I bring it up in the browser (below). Is there any way I can get this to load (even if it means deleting or changing the offending strings)?

      "key": "DEV-87",
      "data": {
        "id": 87,
        "name": "Temperature Time Graph Tile",
        "secondaryName": "webCoRE Graphs Tile Device",
        "type": "webCoRE Graphs Tile Device",
        "source": "System",
        "dni": "webCoRE_83",
        "zigbeeId": null,
        "lastActivity": "2024-04-05T20:46:11+0000",
        "disabled": false,
        "roomId": 0,
        "roomName": "",
        "level": 0,
        "user": false,
        "defaultCurrentState": null,
        "currentStates": [
          {
            "value": "\n\t\u003Cstyle\u003E.tile-primary{height:100%}\u003C/style\u003E\n\t\u003Ciframe style=\"width: 100%; height: 100%;\" src=\"http://192.168.1.137/apps/api/83/graph/?access_token=XXXXXXXXXXXX\" data-fs=\"false\" onload=\"(() =\u003E {\n\t\tconst body = this.contentDocument.body;\n\t\tconst start = () =\u003E {\n\t\t\tif(this.dataset.fs == 'false') {\n\t\t\t\tthis.style = 'position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 999;';\n\t\t\t\tthis.dataset.fs = 'true';\n\t\t\t} else {\n\t\t\t\tthis.style = 'width: 100%; height: 100%;';\n\t\t\t\tthis.dataset.fs = 'false';\n\t\t\t}\n\t\t}\n\t\tbody.addEventListener('dblclick', start);\n\t})()\"\u003E\u003C/iframe\u003E\n\t\n",
            "key": "Graph"
          },
          {
            "value": "\n\t\u003Cstyle\u003E.tile-primary{height:100%}\u003C/style\u003E\n\t\u003Ciframe style=\"width: 100%; height: 100%;\" src=\"http://192.168.1.137/apps/api/83/graph/?access_token=XXXXXXXXXXXX\" data-fs=\"false\" onload=\"(() =\u003E {\n\t\tconst body = this.contentDocument.body;\n\t\tconst start = () =\u003E {\n\t\t\tif(this.dataset.fs == 'false') {\n\t\t\t\tthis.style = 'position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 999;';\n\t\t\t\tthis.dataset.fs = 'true';\n\t\t\t} else {\n\t\t\t\tthis.style = 'width: 100%; height: 100%;';\n\t\t\t\tthis.dataset.fs = 'false';\n\t\t\t}\n\t\t}\n\t\tbody.addEventListener('dblclick', start);\n\t\tthis.parentElement.parentElement.parentElement.querySelector('.tile-title').style='display: none;';\n\t})()\"\u003E\u003C/iframe\u003E\n\n",
            "key": "Graph_No_Title"
          }
        ],
        "hubMesh": false,
        "homekit": false
      },
      "children": [],
      "parent": false,
      "child": false
    },
type or paste code here

Something like this?

const txt = '{"name":"\rJohn", "age":30}'

function replaceNewLines(str) {
  return str.replace(/\r/g, '\\r')
}

console.log(
  JSON.parse(replaceNewLines(txt))
)

Output

{
  "name": "\rJohn",
  "age": 30
}

Edit: A bit of experimentation, this seems to work too

function replaceNewLines(str) {
  return str.replace(/[\r\n]/g, (char) => JSON.stringify(char).slice(1,-1))
}

JSON.stringify converts a return character to '"\r"'. Stripping the double quotes with slice gives us an escaped string version '\r'. The same applies to newline.

So using this stringify version of the function with the following const txt = '{"name":"\rJohn", "age":"\nthirty"}' will parse to

{
  "name": "\rJohn",
  "age": "\nthirty"
}

This approach might make it easier to escape other characters too.

2 Likes

Wonderful, Thanks! I really need to study up on regular expressions.

For clarity, this problem occurs because the system tries to process your escape characters when you do the var txt = line, but what you want it to do is leave them alone. The double-slash tells the string parser that the \ should be left as a literal \ in the stored string; the r is…just an r at that point, the string parser leaves that alone naturally.

JSON.parse then comes along and tries to read your data; a random carriage return (the translated form of \r, ASCII 13) at the start of the string would cause it grief (which is why you get the error), but the literal characters \r just get it a shrug - it’s happy to just chalk those up as-is parts of a string.

Presumably, you’ve got a reason for wanting those control characters left on your data. Personally, i’d have trimmed them off and let my presentation layer handle the formatting.

2 Likes