双引号导致的JSON解析错误

54

即使转义,双引号也会导致解析错误。
看下面的代码:

//parse the json in javascript  
var testJson = '{"result": ["lunch", "\"Show\""] }';  
var tags = JSON.parse(testJson);  
alert (tags.result[1]);

因为双引号已经被转义,所以出现语法解析错误。
即使使用eval()也无法起作用。
但是如果我像这样用双斜杠转义它:

var result = '{"result": ["lunch", "\\"Show\\""] }';  
var tags = JSON.parse(result);  
alert (tags.result[1]);

那么它就能正常工作了。
为什么在javascript中我们需要使用双斜杠?问题是PHP的json_encode()函数会用一个斜杠转义一个双引号(像这样:\"show\"),但是JSON.parse()不能解析。我该如何处理这种情况?

9个回答

35

Javascript会反转义它的字符串,JSON也会进行反转义。第一个字符串('{"result": ["lunch", "\"Show\""] }')在JSON解析器中被视为{"result": ["lunch", ""Show""] },因为在Javascript中,\"表示",但并没有退出双引号字符串。

第二个字符串'{"result": ["lunch", "\\\"Show\\\""] }'首先被反转义为{"result": ["lunch", "\"Show\""] },然后被JSON正确地反转义。

我认为'{"result": ["lunch", "\\"Show\\""] }'也应该可以正常工作。


34

JSON的解析使用了相同的eval函数,所以当你给它们不正确的语法时,它们之间没有区别。在这种情况下,你需要在PHP中正确地转义引号,然后再用json_encode转义它们和它们的转义斜杠。

<?php
    $json = '{"result": ["lunch", "\"Show\""] }';
    echo json_encode($json);
?>

OUTPUT: "{\"result\": [\"lunch\", \"\\\"Show\\\"\"] }"

如果我没有打错字,这应该适用于客户端JavaScript。


2
但这是应该由json_encode()函数来处理的事情。 为什么它返回的内容无法被JSON.parse()正确解析? - Varun
7
这不是json_encode的错误(我假设你是这个意思)。json_encode并不旨在创建JavaScript字符串文字,因此它不会进行额外的转义。 - Matthew Crumley

11

这个问题是由于双重字符串转义机制引起的:一种来自JS,一种来自JSON。

使用反斜杠字符与其后面的另一个字符组合表示在字符串中不能用其他方式表示的一个字符。例如,''\\'' 表示 '\' 等。

此转义机制发生在 JSON.parse() 开始之前。

例如:

var parsedObj = JSON.parse('{"sentence": "It is one backslash(\\\\)"}');
console.log(parsedObj.sentence);
>>>"It is one backslash(\)"

从字符串生成器的角度来看,它会将四个反斜杠'\'传递给JavaScript解释器。

从JavaScript解释器的角度来看,它会将两个反斜杠'\\'解释为一个'\',因为每个'\\'序列都会被解释为一个'\'。

从JSON解析器的角度来看,它接收到两个反斜杠'\\',JSON字符串转义规则将其解析为一个单独的'\',这就是输出结果。

解释你的第一段代码:

var testJson = '{"result": ["lunch", "\"Show\""] }';
//The real string after sequence escaping in to JS is
//'{"result": ["lunch", ""Show""] }' 
//which is passed into the JSON.parse.
//Thus, it breaks the JSON grammar and generates an error
var tags = JSON.parse(testJson);  
alert (tags.result[1]);

10

PHP 转换为 JavaScript 对象(PHP >= 5.3.0)

var storesLocations = JSON.parse('<?php echo addslashes(json_encode($storesLocations,JSON_HEX_APOS | JSON_HEX_QUOT)) ?>');

1
这也是一个非常好的解决方法。它解决了我的问题。 - Vineet Sajwan
这是一个非常好的解决方案。 - Pape

10

文档中得知

JSON_HEX_APOS (整数) 所有的 ' 被转换为 \u0027
JSON_HEX_QUOT (整数) 所有的 " 被转换为 \u0022

json_encode() 函数接受两个参数,值和选项。因此,请尝试使用:

json_encode($result, JSON_HEX_QUOT); // or
json_encode($result, JSON_HEX_QUOT | JSON_HEX_APOS);

我虽然没有尝试过。


1
您正在使用的 PHP 版本低于 5.3.0,正如文档所示。 - raylu
这就是答案,但本来应该是默认行为。 - user1115652

3

php.ini 中关闭 magic_quotes_gpc


0
如果添加了标准的C转义字符,那么JSON.parse将会把像\"这样的序列转换为"\\转换为\\n转换为换行符等。
'foo\\bar\nbaz"' === JSON.parse('"foo\\\\bar\\nbaz\\""')

在我们项目的情况下:
原始字符串 ""{\"lat\":28.4594965,\"lng\":77.0266383}"" 传递给 JSON.parse()
"{"lat":28.4594965,"lng":77.0266383}"

在第二次调用 JSON.parse()

{lat: 28.4594965, lng: 77.0266383}

请注意,JSON.parse() 移除了转义字符而不是将 string 转换为 object
移除转义字符后,字符串到对象的转换就可以正常工作了。
以下是演示:
while (typeof p1 != 'object') {
  p1 = JSON.parse(p1);
  pass++;
  console.log('On pass ', pass, p1);
}

0

这可能会有所帮助:

<?php
$json = '{"result": ["lunch", "\"Show\""] }';
echo addslashes(json_encode($json));

0

试一下这个。然后再试着注释掉

<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<pre><?php ($_POST)?print_r($_POST):'' ?></pre>

<form method="POST">
    <input type="text" name="name"><br>
    <input type="email" name="email"><br>
    <input type="time" name="time"><br>
    <input type="date" name="date"><br>
    <input type="hidden" name="id"><br>
    <textarea name="detail"></textarea>
    <input type="submit" value="Submit"><br>
</form>
<?php 
/* data */
$data = [
            'name'=>'vinay"'."'\\\\",
            'email'=>'imvsrajput@demo.demo',
            'time'=>date('H:i:00'),
            'date'=>date('Y-m-d'),
            'detail'=>'Try this var_dump(0=="ZERO") \\ \\"'." ' \\\\    ",
            'id'=>123,
        ];
?>
<span style="display: none;" class="ajax-data"><?=json_encode($data)?></span>
<script type="text/javascript">
    /* Error */
    // var json = JSON.parse('<?=json_encode($data)?>');
    /* Error solved */
    var json = JSON.parse($('.ajax-data').html());
    console.log(json)
    /* automatically assigned value by name attr */
    for(x in json){
        $('[name="'+x+'"]').val(json[x]);
    }
</script>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接