如何处理被编码两次的JSON?

3

我有以下两组需要解码的代码。

$test = 
'{
    "username":"sophia",
    "event":{
        "failure":"unreset",
        "answers":{
            "question1":"{\"answer\":\"{\\\"pass\\\":true,\\\"mark\\\":9,\\\"totalmark\\\":9,\\\"value\\\":\\\"get full attention|establish classroom rules|teach key words & concepts|use visual aids|demonstrate|check understanding|introduce point system|give handouts|play\\\"}\",\"state\":\"{\\\"result\\\":{\\\"pass\\\":true,\\\"mark\\\":9,\\\"totalmark\\\":9,\\\"value\\\":\\\"get full attention|establish classroom rules|teach key words & concepts|use visual aids|demonstrate|check understanding|introduce point system|give handouts|play\\\"}}\"}"
        }
    },
     "event_source":"server"
}';

首先,尽管它是有效的,但我无法完全解码第一个内容。似乎“question1”部分被加密两次,我不知道出了什么问题。

$test = 
'{
    "username":"lon",
    "event":{
        "saved_response":"{\"parts\": [{\"text\": \"Passion for teaching means loving your job. Doing with all your heart. Teachers who are passionate can inspire pupils to love learning. Passionate teachers create an effective learning environment and increase learning potential of\\nstudents.\"}]}"
    },
    "event_source":"server"
}';

$jarray = json_decode($test, true);
$jevent = json_decode($jarray['event']['saved_response'], true);

对于第二个错误,我可以解码一次,但是var_dump($jevent)的输出为NULL。
有人可以友好地解释一下为什么会出现这两个错误吗?我已经查看了如何处理PHP中JSON字符串中的反斜杠,但现在我真的很困惑。谢谢。

实际上,在一个在线PHP解码器上,两者都成功解码了,并且嵌套的JSON部分也被正确解码了。顺便说一下,如果您可以控制JSON的创建,请防止将JSON数据重新编码为另一个JSON的一部分。 - Kaddath
我使用了 json_last_error_msg() 并获得了一个错误:"控制字符错误,可能是编码不正确"。 - KIKO Software
你的 $test 字符串在解析为 JSON 时无效。但如果它被视为字面文本(例如从文件或网络操作中读取),它是有效的 JSON。你在哪里以及如何接收到这个字符串?(区别在于反斜杠:你需要在 $test 字符串文字中对它们进行转义)。 - T.J. Crowder
1
@CassieLiu - 字符串文字中的反斜杠用于转义下一个字符。如果你从日志中获取包含反斜杠的文本并将其粘贴在 ' 字符之间,则不会创建包含该文本的字符串。例如,文本 testing\fun 中包含一个反斜杠。如果你将它粘贴到一个字符串文字 ('testing\fun') 中,则生成的字符串不会包含反斜杠(它包含了一个回车换行符,因为反斜杠后面加上了转义序列 \f)。要将原始文本转换成字符串文字,必须复制所有反斜杠。文本 testing\fun 变成了字符串文字 'testing\\fun' - T.J. Crowder
1
@CassieLiu - 如果你将JSON粘贴到字符串文字中,那么是的,你需要;如果你从文件或网络套接字等读取JSON,则不需要。JSON仍然很奇怪,但可以解析。正如你所指出的,question1被双重编码,但更糟糕的是其中两个属性(answerstate)也被双重编码(总共四重编码)。 - T.J. Crowder
显示剩余8条评论
3个回答

2
在问题中,您的$test字符串并不准确地反映了您要解析的数据。您说您从日志中复制并粘贴了它,但是当您将包含反斜杠的文本粘贴到字符串文字中时,这些反斜杠不再是反斜杠,它们是转义字符。您必须使用另一个反斜杠对它们进行转义。也就是说,如果您在文本中有testing\foo,并且您将其放入字符串文字中,则需要复制该反斜杠以使文字创建具有相同文本的字符串:'testing\\foo'
因此,为了准确反映您从日志中复制的文本,$test文字应为:
$test = 
'{
    "username":"sophia",
    "event":{
        "failure":"unreset",
        "answers":{
            "question1":"{\\"answer\\":\\"{\\\\\\"pass\\\\\\":true,\\\\\\"mark\\\\\\":9,\\\\\\"totalmark\\\\\\":9,\\\\\\"value\\\\\\":\\\\\\"get full attention|establish classroom rules|teach key words & concepts|use visual aids|demonstrate|check understanding|introduce point system|give handouts|play\\\\\\"}\\",\\"state\\":\\"{\\\\\\"result\\\\\\":{\\\\\\"pass\\\\\\":true,\\\\\\"mark\\\\\\":9,\\\\\\"totalmark\\\\\\":9,\\\\\\"value\\\\\\":\\\\\\"get full attention|establish classroom rules|teach key words & concepts|use visual aids|demonstrate|check understanding|introduce point system|give handouts|play\\\\\\"}}\\"}"
        }
    },
     "event_source":"server"
}';

你所说的,question1 是双重编码的。更糟糕的是,当你解码它时,你会发现它有一个名为 answerstate 的属性,它们再次被双重编码。
要解码所有内容,您必须先解码主要部分,然后解码 question1,最后解码它的 answerstate
"最初的回答"
$obj = json_decode($test);
$obj->event->answers->question1 = json_decode($obj->event->answers->question1);
$obj->event->answers->question1->answer = json_decode($obj->event->answers->question1->answer);
$obj->event->answers->question1->state = json_decode($obj->event->answers->question1->state);

如果您在记录日志时执行此操作,它将起作用。结果(来自var_dump)为:
object(stdClass)#1 (3) {
  ["username"]=>
  string(6) "sophia"
  ["event"]=>
  object(stdClass)#2 (2) {
    ["failure"]=>
    string(7) "unreset"
    ["answers"]=>
    object(stdClass)#3 (1) {
      ["question1"]=>
      object(stdClass)#4 (2) {
        ["answer"]=>
        object(stdClass)#5 (4) {
          ["pass"]=>
          bool(true)
          ["mark"]=>
          int(9)
          ["totalmark"]=>
          int(9)
          ["value"]=>
          string(161) "吸引学生的注意力|建立课堂规则|教授关键词汇和概念|使用视觉辅助工具|演示|检查理解|介绍积分制度|发放手册|玩耍"
        }
        ["state"]=>
        object(stdClass)#6 (1) {
          ["result"]=>
          object(stdClass)#7 (4) {
            ["pass"]=>
            bool(true)
            ["mark"]=>
            int(9)
            ["totalmark"]=>
            int(9)
            ["value"]=>
            string(161) "吸引学生的注意力|建立课堂规则|教授关键词汇和概念|使用视觉辅助工具|演示|检查理解|介绍积分制度|发放手册|玩耍"
          }
        }
      }
    }
  }
  ["event_source"]=>
  string(6) "server"
}
实时复制

1

您需要从第二个json中删除换行符。

尝试这样做:

trim(preg_replace('/\s+/', ' ',$jarray['event']['saved_response'])) - 将多个空格和换行符替换为单个空格。

$test = 
'{
    "username":"lon",
    "event":{
        "saved_response":"{\"parts\": [{\"text\": \"Passion for teaching means loving your job. Doing with all your heart. Teachers who are passionate can inspire pupils to love learning. Passionate teachers create an effective learning environment and increase learning potential of\\nstudents.\"}]}"
    },
    "event_source":"server"
}';

$jarray = json_decode($test, true);
$jevent = json_decode( trim(preg_replace('/\s+/', ' ',$jarray['event']['saved_response'])), true);
var_dump($jarray);
var_dump($jevent);

https://3v4l.org/fnc1V

作为一种替代方案,您可以进行双重转义:
$test = 
'{
    "username":"lon",
    "event":{
        "saved_response":"{\\"parts\\": [{\\"text\\": \\"Passion for teaching means loving your job. Doing with all your heart. Teachers who are passionate can inspire pupils to love learning. Passionate teachers create an effective learning environment and increase learning potential of\\\\nstudents.\\"}]}"
    },
    "event_source":"server"
}';

$jarray = json_decode($test, true);
$jevent = json_decode( $jarray['event']['saved_response'], true);
var_dump($jarray);
var_dump($jevent);

https://3v4l.org/9k3t1

如何处理JSON中的换行符?


但是如果新行被缩进并且需要保留在字符串中呢? - KIKO Software
1
他的JSON无效。在这种情况下,他必须转义那个换行符。 - Andrei Lupuleasa
@AndreiLupuleasa 感谢您的努力!我只是想知道是否有办法保留换行符? - Cassie Liu

0

这将解码您损坏的 JSON 字符串。

$test = 
'{
    "username":"lon",
    "event":{
        "saved_response":"{\"parts\": [{\"text\": \"Passion for teaching means loving your job. Doing with all your heart. Teachers who are passionate can inspire pupils to love learning. Passionate teachers create an effective learning environment and increase learning potential of\\nstudents.\"}]}"
    },
    "event_source":"server"
}';

var_dump(json_decode(preg_replace('/[\x00-\x1F\x80-\xFF]/', '', json_decode($test, true)['event']['saved_response']), true)['parts'][0]['text']);

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