我有一个 JSON 文件,其中包含来自 Clojure 的
data.json
库的 JSON。数据来自推特,人们似乎经常微笑。
$ cat /tmp/myfile | jq .
我得到:
parse error: Invalid \uXXXX\uXXXX surrogate pair escape at line 1, column 14862268
违规部分是:
$ cut -c 14862258-14862269 /tmp/2017-02-23-2
79-7\ud83d",
所以,这个转义码是在真实的 JSON 文件中找到的,而 JQ 无法读取它。
echo '"\ud83d"' | jq .
Fileformat.info 似乎建议它应该成对出现:
SMILING FACE WITH OPEN MOUTH
"\uD83D\uDE03"
这真的是在 JSON 文件中查找的无效字符吗?我的 JSON 在技术上无效吗?
是否有一个简单的实用程序可以在 JQ 之前通过管道传输数据以去除这些字符?或者我可以让JQ放宽它的解释吗?
JSON 规范 说:
字符串是零个或多个 Unicode 字符 [UNICODE] 的序列。
从这个意义上说,字符串“\ud83d”不是有效的 JSON(“+UD83D 不是有效的 Unicode 字符”),即使它符合 JSON ABNF。正如标准文档继续指出的,字符串规范和 ABNF 之间存在差异:
本规范中的 ABNF 允许成员名称和 包含无法编码 Unicode 的位序列的字符串值 人物;例如,“\uDEAD”(单个未配对的 UTF-16 代理人)。已经观察到这种情况的实例,例如,当 库截断 UTF-16 字符串而不检查是否 截断分裂代理对。软件的行为 接收包含此类值的 JSON 文本是不可预测的...
所以可以公平地说:
“\uD83D”不是严格有效的 JSON,即使它符合 ABNF;
jq 在此享有其权利;
jsonlint 接受“\uD83D”是错误的。
参见例如 如何从文本文件中删除非 UTF-8 字符
它绝对是有效的 json,但代码单元
D83D
本身是无效的。请记住,jq 不仅仅是解释 json,它还试图获取它的值。因此,一旦被 jq 使用,它就不再只是存储在 json 中的字符流,而是一个具有确定值的字符串。
该值是一个高代理,它必须成对出现,而您的输入显然没有。因此,文件中编码的字符串虽然是有效的 json,但并不代表 jq 尝试解析的有效 unicode 字符串。
如果您希望能够使用 jq 解析它,您需要检查 json 并完成对。
如果您至少可以确保它是有效的 json,您可能可以使用正则表达式来扫描数据以搜索不匹配的代理。像这样的东西:
\\u[Dd][89ABab][0-9A-Fa-f]{2}(?!\\u[Dd][C-Fc-f][0-9A-Fa-f]{2})
|
(?<!\\u[Dd][89ABab][0-9A-Fa-f]{2})\\u[Dd][C-Fc-f][0-9A-Fa-f]{2}
然后你可以将它们脱掉,或者对丢失的代理进行最佳猜测。
改用 yq (https://github.com/mikefarah/yq),它可以在 jq 失败的大型数据集上不会出现解析错误。