18

I have json data represented like this

{key:"value"}

(no quotes arround key...)

I want to translate it to an associative array.

PHP's json_decode returns null

How can I add the quotes around the key?? thanks...

Bar
  • 229
  • 1
  • 3
  • 7
  • There is not built in function but like said adam looks from where you are getting your JSON to send it properly – Kakawait Aug 04 '11 at 12:53
  • 3
    It's not uncommon for JSON to come across this way, unfortunately. Google does it... http://www.google.com/ig/calculator?hl=en&q=1%20USD=?CAD – Laizer May 22 '13 at 10:39
  • Your link returns a 404 @Laizer and the JSON listed here is *not valid*. – Jay Blanchard Apr 23 '15 at 21:03

9 Answers9

15

You can either fix the JSON at the source so that it returns a valid JSON structure, or you can manually add quotes around the keys.

This answer to a similar question has an example of how to do that:

function my_json_decode($s) {
    $s = str_replace(
        array('"',  "'"),
        array('\"', '"'),
        $s
    );
    $s = preg_replace('/(\w+):/i', '"\1":', $s);
    return json_decode(sprintf('{%s}', $s));
}
Community
  • 1
  • 1
Intelekshual
  • 7,444
  • 1
  • 21
  • 28
  • Thanks for this solution. But I had to remove sprintf('{%s}', $s) and had to use just $s as the argument for json_decode function. – Manjula Nov 03 '11 at 07:09
  • Excellent Solution. I am not sure why Manjula didnt ACCEPT this as the correct answer yet... over 2 years later... – AKKAweb Jan 05 '14 at 16:46
  • @holden321 It's replacing them with keys wrapped in quotes, that's what `$s = preg_replace('/(\w+):/i', '"\1":', $s);` is doing. – Intelekshual Feb 11 '14 at 14:14
  • 9
    Not a valid solution! Try setting a key or "value" to a url or something with a colon in it. This will fail. eg {key:"va:lue"} – KXL Oct 05 '14 at 23:12
  • 1
    preg_replace('/(\n[\s||\t]*)(\w+):[\s||\t]/i', '$1"$2":', $json); – Barry Jul 08 '16 at 16:28
  • I think you should do a `stripslashes()` before doing `json_decode()`. Although this defined custom function handles most situations, this is not a complete solution as @KXL mentioned. – Fr0zenFyr Oct 01 '16 at 06:52
  • If keys are followed by white space, they are missed by this code. Also, the first replace is bad: why replace double quotes with single quotes? If anything this will break JSON syntax even more. And the replacement `array('\"', '"')` is useless: it is a null-operation since both arguments are the same string. – trincot Oct 30 '16 at 07:57
  • 1
    simply does not add any quote to my json..why is this even voted so much – Phil Sep 29 '17 at 08:28
  • The regex part can be approved like this: `$s = preg_replace('/([{,]\s*)(\w+):/is', '\1"\2":', $s);` That would ensure unquoted keys have a { or a , in front of them with any amount of whitespace. This is still an imperfect solution, as it might trip over a value containing either of these. – Andries Mooij Apr 23 '20 at 08:20
11

If you can't turn that into valid JSON at the source, then you can use Services_JSON from PEAR to parse it, since adding quotes around the key is a non-trivial error-prone process.

Services_JSON will correctly parse the invalid key string.

Example:

$json = new Services_JSON();
var_dump($json->decode('{key:"value"}'));

Output:

object(stdClass)#2 (1) {
  ["key"]=>
  string(5) "value"
}
rid
  • 61,078
  • 31
  • 152
  • 193
  • thanks, exactly what i was looking for, and still works in modern versions of PHP after all these years (tested on 7.3) - btw if you want arrays instead of objects then construct it as `$json_decoder = new Services_JSON(SERVICES_JSON_IN_ARR | SERVICES_JSON_LOOSE_TYPE);` – hanshenrik May 13 '19 at 10:24
8

To avoid that double quotes are inserted in places where they shouldn't, you should skip those quoted strings in this manipulation.

For instance, if you have this JavaScript object literal in a string:

{
   dt:"2016-10-22T09:13:20",
   "x:y":false
}

... then care must be taken not to have 22T09: change into "22T09":. Also the already quoted key, "x:y" should stay unaltered.

You could use this regular expression for achieving that:

preg_replace('/("(.*?)"|(\w+))(\s*:\s*(".*?"|.))/s', '"$2$3"$4', $text);

Other issues

JavaScript object literals allow numeric constants with left-padded zeroes, like 001, and/or with the unary + sign, which are neither allowed in JSON. To remove those offending characters also, you could use this extended version:

preg_replace('/("(.*?)"|(\w+))(\s*:\s*)\+?(0+(?=\d))?(".*?"|.)/s', '"$2$3"$4$6', $text);
trincot
  • 317,000
  • 35
  • 244
  • 286
4

DON'T USE REGEX.

REGEX is totally not recommended for such cases, don't use that for parsing such data. If you have a simple goals and want to avoid the stable PEAR package, then you might try JSON-php library (but no-longer maintained).

1) Get JSON.phps file from here and rename to .php and replace constructor function names to __construct.

2) usage:

$content = '{myKey:"valueeeee"}';

include(__DIR__.'/JSON.php'); 
$this->json = new Services_JSON( SERVICES_JSON_LOOSE_TYPE );  // to return objects instead of Associative array, remove the argument
var_dump( $this->json->decode($content)  );
T.Todua
  • 53,146
  • 19
  • 236
  • 237
3

Please do not use regexps to do this! JSON grammar cannot be correctly parsed this way by definition. You will open yourself to a ton of future bugs.

I recommend using a YAML parser, because YAML is a superset of JSON and allows unquoted literals at the same time.

Symfony YAML component works great.

There will be a performance penalty in comparison to json_decode which is implemented natively.

pinkeen
  • 690
  • 3
  • 10
  • 21
2
$results = \Symfony\Component\Yaml\Yaml::parse("{a: d, b: 'c', e: [a, 3]}");

You probably can only use that lib without having to use the whole Symfony package : https://packagist.org/packages/symfony/yaml

Remy Mellet
  • 1,675
  • 20
  • 23
0

This worked for me, using regex replace '/\s(\w+)\s/i'

$json =  file_get_contents("php://input"); // or whatever json data
$json = preg_replace('/\s(\w+)\s/i', '"$1"', $json);
$json = json_decode($json, true);
Madagaga
  • 869
  • 9
  • 11
  • 1
    This will add double quotes inside values, while it will miss the keys if they have no white space around them: `{s:"this is my string", flag: false , n: 9 }` will become `{s:"this"is"my string", flag:"false", n:"9"}`. – trincot Oct 30 '16 at 07:52
  • just add the : in the regex, it should be actually voted as a good answer – Phil Sep 29 '17 at 08:32
0

As per the documentation (see Example #3 - 'common mistakes using json_decode'), keys must be enclosed in double quotes.

Where are you getting the JSON data?

Adam Hopkinson
  • 28,281
  • 7
  • 65
  • 99
0

I tested many of the solutions proposed here and nothing worked correctly.

  • @Intelekshual does not work with more "complex" cases.
$json='{hello:{a:2,b:3},world:[1,2,3,"aaa","bbbb"]}';

var_dump(my_json_decode($json)); // returns null

function my_json_decode($s) {
    $s = str_replace(
        array('"',  "'"),
        array('\"', '"'),
        $s
    );
    $s = preg_replace('/(\w+):/i', '"\1":', $s);
    return json_decode(sprintf('{%s}', $s));
}
  • @rid and @T.Todua the library does not work because the code targets PHP 4.x/5.x and it has many deprecated features.

So I created an adaptation of Services_JSON (PECL) and updated the code to PHP 7.2 and higher (including PHP 8.1). It works with Composer and it doesn't have any other dependency.

https://github.com/EFTEC/Services_JSON

Or you could copy and paste the code from here:

https://github.com/EFTEC/Services_JSON/blob/main/src/Services_JSON.php

magallanes
  • 6,583
  • 4
  • 54
  • 55