Как исправить плохо форматированный JSON в PHP?

Я получаю канал данных, который находится в формате JSON и единственный доступный формат. В PHP я использую json_decode для декодирования JSON, но он ломался, и я узнал, что JSON был сгенерирован в некоторых местах с двойными кавычками в псевдониме человека. Я проверил это, используя: http://jsonformatter.curiousconcept.com

У меня нет контроля над созданием данных, но мне приходится иметь дело с этим сломанным форматом, когда это происходит. Эти данные после его анализа будут помещены в таблицу MySQL TABLE.

Например:

"contact1": "David "Dave" Letterman", 

json_decode вернет NULL. Если бы я вручную сохранил файл и изменил его на одинарные кавычки вокруг прозвища Dave, тогда все сработало.

 $json_string = file_get_contents($json_download); $json_array = json_decode($json_string, true); 

Как исправить разбитый формат JSON в json_string до того, как он обработает json_decode? Что нужно сделать для предварительной обработки файла, обратная косая черта двойных кавычек прозвища? Или изменить их на одинарные кавычки? Это даже хорошая идея хранить двойные кавычки, подобные этому в MySQL?

Я не знаю, когда это может произойти с каждым фидом данных, поэтому я не хочу просто проверять контакт1, если у него есть внутренние двойные кавычки, чтобы исправить их. Есть ли способ в PHP взять строку, такую ​​как приведенный выше пример, и обратная косая черта после двоеточия, кроме внешних двойных кавычек? Благодаря!

Это правильный код, как указано в tftd:

 <?php // This: // "contact1": "David "Dave" Letterman", // Needs to look like this to be decoded by JSON: // "contact1": "David \"Dave\" Letterman", $data ='"contact1": "David "Dave" Letterman",'; function replace($match){ $key = trim($match[1]); $val = trim($match[2]); if($val[0] == '"') $val = '"'.addslashes(substr($val, 1, -1)).'"'; else if($val[0] == "'") $val = "'".addslashes(substr($val, 1, -1))."'"; return $key.": ".$val; } $preg = preg_replace_callback("#([^{:]*):([^,}]*)#i",'replace',$data); var_dump($preg); $json_array = json_decode($preg); var_dump($json_array); echo $json_array . "\n"; echo $preg . "\n"; ?> 

Вот результат:

 string(39) ""contact1": "David \"Dave\" Letterman"," NULL "contact1": "David \"Dave\" Letterman", 

Как уже указывали другие, лучше всего сообщить своему клиенту о проблеме с форматированием JSON. Попросите их отправить отчет об ошибках оригинальному разработчику / компании, чтобы они могли это исправить. Если он / они не могут это исправить, предложите свое решение. Вам просто нужно addslashes строку, прежде чем вы json_encode .

Если по какой-то причине вам придется fix форматирование, вот что может сработать для вас:

 $data = '"contact1": "David "Dave" Letterman", "contact2": "Peter "Robert" Smith",{\'test\': \'working "something"\'}'; function replace($match){ $key = trim($match[1]); $val = trim($match[2]); if($val[0] == '"') $val = '"'.addslashes(substr($val, 1, -1)).'"'; else if($val[0] == "'") $val = "'".addslashes(substr($val, 1, -1))."'"; return $key.": ".$val; } $preg = preg_replace_callback("#([^{:]*):([^,}]*)#i",'replace',$data); var_dump($preg); // string '"contact1": "David \"Dave\" Letterman", "contact2": "Peter \"Robert\" Smith",{'test': 'working \"something\"'}' (length=110) 

Имейте в виду, что это может сломаться, если кто-то снова испортит формат json.

У меня есть собственная функция jsonFixer () – она ​​работает в два этапа: удаление мусора (для обеспечения равномерности некогерентного форматирования) и переформатирование.

 <?php function jsonFixer($json){ $patterns = []; /** garbage removal */ $patterns[0] = "/([\s:,\{}\[\]])\s*'([^:,\{}\[\]]*)'\s*([\s:,\{}\[\]])/"; //Find any character except colons, commas, curly and square brackets surrounded or not by spaces preceded and followed by spaces, colons, commas, curly or square brackets... $patterns[1] = '/([^\s:,\{}\[\]]*)\{([^\s:,\{}\[\]]*)/'; //Find any left curly brackets surrounded or not by one or more of any character except spaces, colons, commas, curly and square brackets... $patterns[2] = "/([^\s:,\{}\[\]]+)}/"; //Find any right curly brackets preceded by one or more of any character except spaces, colons, commas, curly and square brackets... $patterns[3] = "/(}),\s*/"; //JSON.parse() doesn't allow trailing commas /** reformatting */ $patterns[4] = '/([^\s:,\{}\[\]]+\s*)*[^\s:,\{}\[\]]+/'; //Find or not one or more of any character except spaces, colons, commas, curly and square brackets followed by one or more of any character except spaces, colons, commas, curly and square brackets... $patterns[5] = '/["\']+([^"\':,\{}\[\]]*)["\']+/'; //Find one or more of quotation marks or/and apostrophes surrounding any character except colons, commas, curly and square brackets... $patterns[6] = '/(")([^\s:,\{}\[\]]+)(")(\s+([^\s:,\{}\[\]]+))/'; //Find or not one or more of any character except spaces, colons, commas, curly and square brackets surrounded by quotation marks followed by one or more spaces and one or more of any character except spaces, colons, commas, curly and square brackets... $patterns[7] = "/(')([^\s:,\{}\[\]]+)(')(\s+([^\s:,\{}\[\]]+))/"; //Find or not one or more of any character except spaces, colons, commas, curly and square brackets surrounded by apostrophes followed by one or more spaces and one or more of any character except spaces, colons, commas, curly and square brackets... $patterns[8] = '/(})(")/'; //Find any right curly brackets followed by quotation marks... $patterns[9] = '/,\s+(})/'; //Find any comma followed by one or more spaces and a right curly bracket... $patterns[10] = '/\s+/'; //Find one or more spaces... $patterns[11] = '/^\s+/'; //Find one or more spaces at start of string... $replacements = []; /** garbage removal */ $replacements[0] = '$1 "$2" $3'; //...and put quotation marks surrounded by spaces between them; $replacements[1] = '$1 { $2'; //...and put spaces between them; $replacements[2] = '$1 }'; //...and put a space between them; $replacements[3] = '$1'; //...so, remove trailing commas of any right curly brackets; /** reformatting */ $replacements[4] = '"$0"'; //...and put quotation marks surrounding them; $replacements[5] = '"$1"'; //...and replace by single quotation marks; $replacements[6] = '\\$1$2\\$3$4'; //...and add back slashes to its quotation marks; $replacements[7] = '\\$1$2\\$3$4'; //...and add back slashes to its apostrophes; $replacements[8] = '$1, $2'; //...and put a comma followed by a space character between them; $replacements[9] = ' $1'; //...and replace by a space followed by a right curly bracket; $replacements[10] = ' '; //...and replace by one space; $replacements[11] = ''; //...and remove it. $result = preg_replace($patterns, $replacements, $json); return $result; } ?> 

Пример использования:

 <?php // Received badly formatted json: // {"contact1": "David "Dave" Letterman", price : 30.00, 'details' : "Greatest 'Hits' Album"} $json_string = '{"contact1": "David "Dave" Letterman", price : 30.00, \'details\' : "Greatest \'Hits\' Album"}'; jsonFixer($json_string); ?> 

Приведет к:

 {"contact1": "David \"Dave\" Letterman", "price" : "30.00", "details" : "Greatest \'Hits\' Album"} 

Примечание: это не было протестировано со всеми возможными сильно форматированными строками JSON, но я использую сложную многоуровневую строку JSON и хорошо работает до тех пор.

Как говорили другие люди, вы можете выполнять поиск и замену, но сложная часть будет создавать ваши правила нечеткого соответствия, потому что для ее анализа вам нужно будет принять некоторые вещи. Возможно, вам нужно будет предположить:

1a) Ключи не содержат двоеточий
1b) или ключевые кавычки правильно экранированы
а также
2a) Значения не содержат запятых
2b), или значения имеют надлежащим образом экранированные кавычки.

Даже тогда вы можете попасть в ситуации, когда ваш синтаксический разбор запутался, и становится хуже, если у них есть комментарии к их JSON. (Не соответствует, но очень часто.)

Теперь, в зависимости от данных, вы можете использовать новые строки, чтобы решить, когда вы смотрите на новый ключ, но опять же, это не является надежным, и вы начинаете делать большие предположения.

Короче говоря, вам нужно либо сделать некоторые предположения, которые могут быть ошибочными в любое время, либо вам нужно заставить их исправить данные.

Скажите им, чтобы они избежали своих строк перед выходом. Вы можете даже предложить исправить это или предоставить решение для кода.

В противном случае вы можете использовать preg_replace с выражением регулярного выражения

См. Замена указанных двойных кавычек в тексте с помощью preg_replace