我尝试解析JSON时遇到问题。我用PHP创建了我的JSON“by my hand”:
$outp ='{"records":['.$outp.']}';
我创建了它,因此我可以从我的数据库中取字段以在页面中显示它们。问题是,在我的数据库中,我有一个字段“描述”,人们可以在其中对某些内容进行描述。所以有些人会像这样返回到行:
Interphone
Equipe:
Canape-lit
Autre:
Local
当我尝试解析我的JSON时,由于这些行的返回而出现错误。 “SyntaxError:意外的令牌”。
以下是我的JSON示例:
{"records":[{"Parking":"Aucun","Description":"Interphone
Equipé :
Canapé-lit
","Chauffage":"Fioul"}]}
有人能帮助我吗?
答案 0 :(得分:1)
你真的把自己挖到了一个非常糟糕的洞里。
您遇到的问题是换行符(换行符和回车符)是无效的JSON。必须将其转义为\n
和\r
。您可以在此处查看完整的JSON标准here。
你需要做两件事。
尽管JSON标准相对简单,但您应该不手动创建JSON。你已经知道为什么了。你必须处理几个边缘情况等。您的用户可以在页面上输入任何,您需要确保无论如何都能正确编码。
您需要使用JSON序列化工具。 json_encode
自5.2起构建。如果您出于任何原因无法使用此功能,请使用JSON序列化程序查找现有的,广泛使用的(因此经过严格测试的)第三方库。
如果您要问,"为什么我不能创建自己的序列化程序?",理论上你可以。实际上,没有意义。你的胜利不如现有的好。与许多人在生产中使用的东西相比,它更容易出现错误并且表现更差。创建和测试也需要比使用现有的更长的时间。
如果在将数据从数据库中拉出后需要在代码中使用此数据,那么您需要一个JSON反序列化器。 json_decode
也应该没问题,但如果你不能使用它,那就找一个广泛使用的第三方库。
如果你还没有投入生产,你真的在这里躲过了一个子弹,你可以跳过整个部分。如果您已经投入生产并且有来自用户的数据,那么您就会遇到一个重大问题。
即使您修复了代码,您的生产数据库中仍然会有错误的数据无法正确解析。您有做某事来使这些数据可用。不幸的是,不可能为每种可能的情况自动恢复原始数据。这是因为用户可能已输入您添加到数据中的字符/子字符串,以将其转换为" JSON&#34 ;;例如,他们可能输入了以逗号分隔的引用词组列表:"dog","cat","pig", and "cow"
。这是一个棘手的问题,因为你知道你没有正确地序列化所有输入输入。没有办法区分生成的代码文本和用户输入的文本之间的区别。当你无法在代码中解决问题时,你将不得不尽心尽力并尝试抛出错误,并且在某些特殊情况下它可能会弄乱用户的数据。您可能需要手动修复一些事情。
首先与您的经理,团队负责人讨论此事,无论您回答谁。假设您无法丢失数据,这是为数据创建修补程序时最合理的流程:
如果您的数据修复无效(可能是因为您没有想到边缘情况或其他内容),那么您可以恢复一个很好的备份,并且可以取消发布。然后回到第1步。
至于如何你可以修复数据,我不建议在这里查询。我推荐一个小脚本工具。它必须从数据库加载数据,拉开字符串,尝试识别所有部分,从这些部分构建对象,最后将它们正确地序列化为JSON,然后将它们放回数据库中。
这是一个关于如何将字符串分开的示例函数:
const ELEMENT_SEPARATOR = '","';
const PAIR_SEPARATOR = '":"';
function recover_object_from_malformed_json($malformed_json, $known_keys) {
$tempData = substr($malformed_json, 14); // Removes {"records":[{" prefix
$tempData = substr($tempData, 0, -4); // Removes "}]} suffix
$tempData = explode(ELEMENT_SEPARATOR, $tempData); // Split into what we think are pairs
$data = array();
$lastKey = NULL;
foreach ($tempData as $i) {
$explodedI = explode(KEY_VALUE_SEPARATOR, $i, 2); // Split what we think is a key/value into key and value
if (in_array($explodedI[0], $known_keys)) { // Check if it's actually a key
// It's a key
$lastKey = $explodedI[0];
if (array_key_exists($lastKey, $data)) {
throw new RuntimeException('Duplicate key: ' + $lastKey);
}
// Assign the value to the key
$data[$lastKey] = $explodedI[1];
}
else {
// This isn't a key vlue pair, near as we can tell
// So it must actually be part of the last value,
// and the user actually entered the delimiter as part of the value.
if (is_null($lastKey)) {
// This one is REALLY messed up
throw new RuntimeException('Does not begin with a known key');
}
$data[$lastKey] += ELEMENT_SEPARATOR;
$data[$lastKey] += $i;
}
}
return $data;
}
请注意,我假设你的"列表"是一个单一的元素。如果您有多个,这会变得更加困难和麻烦。您还需要提前知道您希望拥有哪些密钥。最重要的是,您必须撤消您的代码所做的任何事情,以创建" JSON",并且您必须尽一切努力来尽量不让用户陷入困境&#39 ; s数据。
您可以使用以下内容:
$knownKeys = ["Parking", "Description", "Chauffage"];
// Fetch your rows and loop over them
foreach ($dbRows as $row) {
try {
$dataFromDb = $row.myData // or however you would pull out this string.
$recoveredData = recover_object_from_malformed_json($dataFromDb);
// Save it back to the DB
$row.myData = json_encode($recoveredData);
// Make sure to commit here.
}
catch (Exception $e) {
// Log the row's ID, the content that couldn't be fixed, and the exception
// Make sure to roll back here
}
}
(请原谅我,如果数据库的东西看起来真的很糟糕。我不做PHP,所以我不知道代码应该怎么样。希望你至少可以得到这个概念。)
底线是您的数据库中的数据不是 JSON。如果您尝试解析它,那么您没有正确处理的所有其他边缘情况将在此过程中被搞砸。你会看到像
这样的坏事\\
变为\
\j
变为j
\t
成为制表符最后,它会使你的数据更加混乱。
这是一个巨大的混乱,您应该从不尝试将某些内容转换为标准格式,而无需使用经过适当构建且经过良好测试的序列化程序。修复数据会很困难,而且需要时间。我也非常怀疑你在文本处理技术方面有很多背景,而缺乏这些知识会使这更难。通过研究编译器的制作方法,您可以获得有关文本处理的一些好信息。祝你好运。