135

I have a string

str = "{'a':1}";
JSON.parse(str);
VM514:1 Uncaught SyntaxError: Unexpected token '(…)

How can I parse the above string (str) into a JSON object ?

This seems like a simple parsing. It's not working though.

Inigo
  • 12,186
  • 5
  • 41
  • 70
Coderaemon
  • 3,619
  • 6
  • 27
  • 50
  • 15
    Single quotes are not correctly formatted json, so if you're receiving something like that, you'd probably need to use str.replace() and replace single qoutes with " before trying to parse it – aup Mar 16 '16 at 14:27
  • 1
    You should anyway always try to use single quotes for strings in javascript. `var str = "bad example";` is not good practice, better do the following: `var str = 'good example';` => like this you won't have any problems with JSON and you wont have any problems with HTML either. :) – ReeCube Mar 16 '16 at 14:30
  • 5
    @ReeCube That seems little more than an opinion--there's no problem with HTML anyway, it accepts both. For JSON, why create it with strings anyway? I don't actually recall the last time I built JSON out of anything other than an object. – Dave Newton Mar 16 '16 at 14:33
  • the whole web development is a mess. and enforce strict rule for no discerning reason seems stupid. IMO.. where is good reason to allow swapping single and double quote at will.. it works in python. and it should work in json. for example try to write hardcoded json in your code and you get bunch of escaped quotes.. so many that you can hardly read which defies purpose of json as a clean text format.. the dev community sways from one extreme to another without hanging on a reasonable ground. – Boppity Bop Mar 15 '23 at 13:36

10 Answers10

115

The JSON standard requires double quotes and will not accept single quotes, nor will the parser.

If you have a simple case with no escaped single quotes in your strings (which would normally be impossible, but this isn't JSON), you can simple str.replace(/'/g, '"') and you should end up with valid JSON.

ssube
  • 47,010
  • 7
  • 103
  • 140
  • 17
    Your answer will tamper with data. A good answer would change the structure and not the data inside the data structure. – Timothy Gonzalez Dec 16 '19 at 17:52
  • 30
    @ssube, global replacing single quotes with double ones is the first that comes to the mind and is a slipshod method, because it can destroy the dictionary values. E.g. `'title': "Mama's Friend"` will become `"title": "Mama"s Friend"`, which is of course invalid! I should downvote your reply but I am against downvoting. This comment is worth much more. – Apostolos Jul 02 '20 at 08:09
  • Hi @Apostolos I agree with you and I now face the same issue. Were you able to find a solution? Thanks in advance – Selvam Raju Mar 22 '21 at 06:20
  • Yes, I found a solution @Selvam, but it's a long time ago but I can't remember what was it since I very rarely use JSON stuff these days. Sorry! :( – Apostolos Mar 23 '21 at 10:45
  • No problem. Thanks for responding @Apostolos – Selvam Raju Mar 24 '21 at 11:31
  • what if a string is - `{a:A}`? How can we parse this? – Tanmay Bairagi Mar 24 '22 at 06:39
52

I know it's an old post, but you can use JSON5 for this purpose.

<script src="json5.js"></script>
<script>JSON.stringify(JSON5.parse('{a:1}'))</script>
Min
  • 530
  • 4
  • 4
19

If you are sure your JSON is safely under your control (not user input) then you can simply evaluate the JSON. Eval accepts all quote types as well as unquoted property names.

var str = "{'a':1}";
var myObject = (0, eval)('(' + str + ')');

The extra parentheses are required due to how the eval parser works. Eval is not evil when it is used on data you have control over. For more on the difference between JSON.parse and eval() see JSON.parse vs. eval()

Jack G
  • 4,553
  • 2
  • 41
  • 50
  • 4
    Even if you think eval is not evil in this case, JSON.parse is always faster: https://jsperf.com/json-parse-vs-eval/3 – Arkanoid Dec 29 '19 at 20:51
  • 5
    @Arkanoid The benchmark you linked to does not apply to this case as it uses only valid JSON (due to JSON.stringify) – syockit Apr 16 '20 at 11:46
  • Good points, so you can get the js object that corresponds to your data – Ben Dev May 23 '22 at 19:49
8

Using single quotes for keys are not allowed in JSON. You need to use double quotes.

For your use-case perhaps this would be the easiest solution:

str = '{"a":1}';

Source:

If a property requires quotes, double quotes must be used. All property names must be surrounded by double quotes.

Jonathan.Brink
  • 23,757
  • 20
  • 73
  • 115
7
var str =  "{'a':1}";
str = str.replace(/'/g, '"')
obj = JSON.parse(str);
console.log(obj);

This solved the problem for me.

Vaishnavi Dongre
  • 241
  • 3
  • 11
7
// regex uses look-forwards and look-behinds to select only single-quotes that should be selected
const regex = /('(?=(,\s*')))|('(?=:))|((?<=([:,]\s*))')|((?<={)')|('(?=}))/g;
str = str.replace(regex, '"');
str = JSON.parse(str);

The other answers simply do not work in enough cases. Such as the above cited case: "title": "Mama's Friend", it naively will convert the apostrophe unless you use regex. JSON5 will want the removal of single quotes, introducing a similar problem.

Warning: although I believe this is compatible with all situations that will reasonably come up, and works much more often than other answers, it can still break in theory.

Sean AH
  • 486
  • 4
  • 8
  • This fails on the first quote after a newline in a new object. Add in a `{` with the `[:,]` to ensure it catches it: `/('(?=(,\s*')))|('(?=:))|((?<=([{:,]\s*))')|((?<={)')|('(?=}))/g` – zaius Jun 02 '23 at 06:41
6

Something like this:

var div = document.getElementById("result");

var str = "{'a':1}";
  str = str.replace(/\'/g, '"');
  var parsed = JSON.parse(str);
  console.log(parsed);
  div.innerText = parsed.a;
<div id="result"></div>
aup
  • 800
  • 7
  • 19
0

sometimes you just get python data, it looks a little bit like json but it is not. If you know that it is pure python data, then you can eval these data with python and convert it to json like this:

echo "{'a':1}" | /usr/bin/python3 -c "import json;print(json.dumps(eval(input())))"

Output:

{"a": 1}

this is good json.

if you are in javascript, then you could use JSON.stringify like this:

data = {'id': 74,'parentId': null};
console.log(JSON.stringify(data));

Output:

> '{"id":74,"parentId":null}'
Oliver Gaida
  • 1,722
  • 7
  • 14
-4

If you assume that the single-quoted values are going to be displayed, then instead of this:

str = str.replace(/\'/g, '"');

you can keep your display of the single-quote by using this:

str = str.replace(/\'/g, '\&apos;\');

which is the HTML equivalent of the single quote.

kyun
  • 9,710
  • 9
  • 31
  • 66
-14
json = ( new Function("return " + jsonString) )(); 
Sterling Archer
  • 22,070
  • 18
  • 81
  • 118
  • 1
    Please explain your answers – Sterling Archer Apr 06 '18 at 00:33
  • 6
    Guys, don't ever do this. This is super unsafe – jpumford Jan 23 '19 at 20:11
  • 1
    The principal of using `Function` instead of eval is sound, but everything else is wrong. It should be `var json = Function("'use strict';return " + jsonString)()` – Jack G Apr 15 '20 at 17:51
  • 4
    Don't get the comments here. This COULD be unsafe, not unsafe in any implementation, same as many APIS!. It's funny to me that this answer got 10+ downvotes while the answer with 'eval' got 15+ vote ups when THEY ARE "UNSAFE" IN EXACTLY THE SAME WAY. When there is no chance for user input to be evaluated, there is NO RISK AT ALL! Using Function constructor for instead of 'eval', is perfectly fine, and much more elegant to do. – Adi Darachi Apr 18 '21 at 17:17
  • 1
    How is the function constructor more elegant than eval? They do pretty much the same thing except one is obfuscated and the other isn't. This answer could at least add a few words of caution, considering if `jsonString` is untrusted, your client can execute arbitrary code. Seems reasonable to act with some discretion or at least show a simple warning when you're giving someone the code equivalent of a box of TNT. – ggorlen Oct 01 '22 at 22:19