如何json_decode无效的JSON与撇号而不是引号

时间:2013-12-03 10:20:33

标签: php json

示例代码:

<?php

$json = "['foo', 'bar']";

var_dump( json_decode($json) );

适用于 PHP 5.5.3 ,但对于较低版本的PHP版本无效

它可以在我的机器上使用PHP 5.5.3,但在其他任何地方都失败了。

我知道这是不正确的JSON,但我的网络服务为我提供了带有'符号的JSON以及"

['foo', "bar", {'test': "crazy \"markup\""}]

Sandbox

如何在PHP 5.3中使用撇号解析JSON数据? 显然我想要解析的原始JSON更复杂。

(我无法在生产服务器上升级我的PHP,也无法从webservice获取正确的JSON)

7 个答案:

答案 0 :(得分:32)

以下是此问题的替代解决方案:

function fixJSON($json) {
    $regex = <<<'REGEX'
~
    "[^"\\]*(?:\\.|[^"\\]*)*"
    (*SKIP)(*F)
  | '([^'\\]*(?:\\.|[^'\\]*)*)'
~x
REGEX;

    return preg_replace_callback($regex, function($matches) {
        return '"' . preg_replace('~\\\\.(*SKIP)(*F)|"~', '\\"', $matches[1]) . '"';
    }, $json);
}

这种方法在两个方面比h2ooooooo的功能更强大:

  • 通过对其应用额外的转义,保留单引号字符串中出现的双引号。 h2o的变体将用双引号替换它们,从而改变字符串的值。
  • 它将正确处理转义的双引号\",因为h2o的版本似乎进入无限循环。

测试:

$brokenJSON = <<<'JSON'
['foo', {"bar": "hel'lo", "foo": 'ba"r ba\"z', "baz": "wor\"ld ' test"}]
JSON;

$fixedJSON = fixJSON($brokenJSON);
$decoded = json_decode($fixedJSON);

var_dump($fixedJSON);
print_r($decoded);

输出:

string(74) "["foo", {"bar": "hel'lo", "foo": "ba\"r ba\"z", "baz": "wor\"ld ' test"}]"
Array
(
    [0] => foo
    [1] => stdClass Object
        (
            [bar] => hel'lo
            [foo] => ba"r ba"z
            [baz] => wor"ld ' test
        )
)

答案 1 :(得分:6)

这是一个简单的解析器,可以为您修复报价。如果它遇到不在双引号'中的"引用,它将假定它是错误的并替换该引号内的双引号,并将引号括起来用双引号:

示例

<?php
    function fixJSON($json) {
        $newJSON = '';

        $jsonLength = strlen($json);
        for ($i = 0; $i < $jsonLength; $i++) {
            if ($json[$i] == '"' || $json[$i] == "'") {
                $nextQuote = strpos($json, $json[$i], $i + 1);
                $quoteContent = substr($json, $i + 1, $nextQuote - $i - 1);
                $newJSON .= '"' . str_replace('"', "'", $quoteContent) . '"';
                $i = $nextQuote;
            } else {
                $newJSON .= $json[$i];
            }
        }

        return $newJSON;
    }

    $brokenJSON = "['foo', {\"bar\": \"hel'lo\", \"foo\": 'ba\"r'}]";
    $fixedJSON = fixJSON( $brokenJSON );

    var_dump($fixedJSON);

    print_r( json_decode( $fixedJSON ) );
?>

<强>输出

string(41) "["foo", {"bar": "hel'lo", "foo": "ba'r"}]"
Array
(
    [0] => foo
    [1] => stdClass Object
        (
            [bar] => hel'lo
            [foo] => ba'r
        )

)

DEMO

答案 2 :(得分:4)

一种解决方案是使用NodeJS构建代理。 NodeJS会正常处理有问题的JSON并返回一个干净的版本:

johan:~ # node
> JSON.stringify(['foo', 'bar']);
'["foo","bar"]'

也许编写一个简单的Node脚本,将JSON数据作为STDIN接受,并将经过验证的JSON返回给STDOUT。这样你可以用PHP调用它。

缺点是您的服务器需要NodeJS。不确定这对你来说是否有问题。

答案 3 :(得分:3)

NikiCs´ answer已经出现了。您的输入似乎是手动生成的,因此完全有可能在'单引号字符串中,您会收到不带引号的"双打。因此,建议使用正则表达式assertion,而不是简单的搜索和替换。

但是也有一些userland JSON解析器支持更多的Javascript表达式语法。此时最好谈论 JSOL ,JavaScript Object Literals。

PEAR Services_JSON

Services_JSON可以解码:

  • 不带引号的对象键
  • 和用单引号括起来的字符串。

不需要其他选项,只需= (new Services_JSON)->decode($jsol);

<{3}} 中的

up_json_decode()

这实际上意味着没有JSON扩展的早期PHP版本的后备。它重新实现了PHP upgradephp。但是还有upgrade.php.prefixed版本,你可以在这里使用。
它引入了另一个标志JSON_PARSE_JAVASCRIPT

up_json_decode($jsol, false, 512, JSON_PARSE_JAVASCRIPT);

我完全忘记在文档中提及这一点,但它也支持单引号字符串 例如:

{ num: 123, "key": "value", 'single': 'with \' and unquoted " dbls' } 

将解码为:

stdClass Object
(
    [num] => 123
    [key] => value
    [single] => with ' and unquoted " double quotes
)

其他选项

  • json_decode() JasonDecoder ArtisticPhoenix确实支持不带引号的键和文字,但没有' - 引用字符串。然而,它很容易理解或扩展。

  • YAML(1.2)是JSON的超集,大多数@支持不带引号的键或单引号字符串。另请参阅parsers

显然,userland中的任何JSOL tokenizer / parser都比预处理格式错误的JSON慢得多。如果您不希望从您的网络服务中获得进一步的问题,请转而使用正则表达式/报价转换。

答案 4 :(得分:2)

如果您知道PHP 5.5。+将优雅地解析此JSON,我会通过PHP5.5 + Web服务器上的代理脚本管理Web服务响应,该服务器会对较低版本的响应进行清理 - 这意味着{{1 }};这是一种稳定可靠的方法。

如果您通过配置值配置Web服务URL,则可以通过访问代理来使用较低版本,通过直接访问Web服务获得更高版本。

答案 5 :(得分:0)

您可以使用(并可能修改/扩展)库来从提供的JSON构建AST,并用双引号替换单引号。

https://github.com/Seldaek/jsonlint/blob/master/src/Seld/JsonLint/Lexer.php

可能是一个好的开始。

答案 6 :(得分:0)

快速解决方案可能是str_replace("'","\"",$string)。这取决于很多事情,但我认为你可以尝试一下。