Matt Cashatt
Matt Cashatt

Reputation: 24218

Parsing malformed JSON in JavaScript

Thanks for looking!

BACKGROUND

I am writing some front-end code that consumes a JSON service which is returning malformed JSON. Specifically, the keys are not surrounded with quotes:

{foo: "bar"}

I have NO CONTROL over the service, so I am correcting this like so:

var scrubbedJson = dirtyJson.replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2": ');

This gives me well formed JSON:

{"foo": "bar"}

Problem

However, when I call JSON.parse(scrubbedJson), I still get an error. I suspect it may be because the entire JSON string is surrounded in double quotes but I am not sure.

UPDATE

This has been solved--the above code works fine. I had a rogue single quote in the body of the JSON that was returned. I got that out of there and everything now parses. Thanks. Any help would be appreciated.

Upvotes: 1

Views: 15596

Answers (5)

John L
John L

Reputation: 1

I was trying to solve the same problem using a regEx in Javascript. I have an app written for Node.js to parse incoming JSON, but wanted a "relaxed" version of the parser (see following comments), since it is inconvenient to put quotes around every key (name). Here is my solution:

var objKeysRegex = /({|,)(?:\s*)(?:')?([A-Za-z_$\.][A-Za-z0-9_ \-\.$]*)(?:')?(?:\s*):/g;// look for object names
var newQuotedKeysString = originalString.replace(objKeysRegex, "$1\"$2\":");// all object names should be double quoted
var newObject = JSON.parse(newQuotedKeysString);

Here's a breakdown of the regEx:

  • ({|,) looks for the beginning of the object, a { for flat objects or , for embedded objects.
  • (?:\s*) finds but does not remember white space
  • (?:')? finds but does not remember a single quote (to be replaced by a double quote later). There will be either zero or one of these.
  • ([A-Za-z_$\.][A-Za-z0-9_ \-\.$]*) is the name (or key). Starts with any letter, underscore, $, or dot, followed by zero or more alpha-numeric characters or underscores or dashes or dots or $.
  • the last character : is what delimits the name of the object from the value.

Now we can use replace() with some dressing to get our newly quoted keys:

originalString.replace(objKeysRegex, "$1\"$2\":")

where the $1 is either { or , depending on whether the object was embedded in another object. \" adds a double quote. $2 is the name. \" another double quote. and finally : finishes it off. Test it out with

{keyOne: "value1", $keyTwo: "value 2", key-3:{key4:18.34}}

output:

{"keyOne": "value1","$keyTwo": "value 2","key-3":{"key4":18.34}}

Some comments:

  • I have not tested this method for speed, but from what I gather by reading some of these entries is that using a regex is faster than eval()
  • For my application, I'm limiting the characters that names are allowed to have with ([A-Za-z_$\.][A-Za-z0-9_ \-\.$]*) for my 'relaxed' version JSON parser. If you wanted to allow more characters in names (you can do that and still be valid), you could instead use ([^'":]+) to mean anything other than double or single quotes or a colon. You can have all sorts of stuff in here with this expression, so be careful.
  • One shortcoming is that this method actually changes the original incoming data (but I think that's what you wanted?). You could program around that to mitigate this issue - depends on your needs and resources available.

Hope this helps. -John L.

Upvotes: 0

Guy
Guy

Reputation: 13326

How about?

function fixJson(json) {
    var tempString, tempJson, output;

    tempString = JSON.stringify(json);
    tempJson = JSON.parse(tempString);
    output = JSON.stringify(tempJson);

    return output;
}

Upvotes: -1

katzmopolitan
katzmopolitan

Reputation: 1391

There is a project that takes care of all kinds of invalid cases in JSON https://github.com/freethenation/durable-json-lint

Upvotes: 0

csuwldcat
csuwldcat

Reputation: 8249

You can avoid using a regexp altogether and still output a JavaScript object from a malformed JSON string (keys without quotes, single quotes, etc), using this simple trick:

var jsonify = (function(div){
  return function(json){
    div.setAttribute('onclick', 'this.__json__ = ' + json);
    div.click();
    return div.__json__;
  }
})(document.createElement('div'));

// Let's say you had a string like '{ one: 1 }' (malformed, a key without quotes)
// jsonify('{ one: 1 }') will output a good ol' JS object ;)

Here's a demo: http://codepen.io/csuwldcat/pen/dfzsu (open your console)

Upvotes: 3

Adam MacDonald
Adam MacDonald

Reputation: 1958

something like this may help to repair the json ..

$str='{foo:"bar"}';
echo preg_replace('/({)([a-zA-Z0-9]+)(:)/','$1"$2"${3}',$str);

Output:

{"foo":"bar"}

EDIT:

var str='{foo:"bar"}';
str.replace(/({)([a-zA-Z0-9]+)(:)/,'$1"$2"$3')

Upvotes: 2

Related Questions