我用的是Facebook feature to download all my data。生成的zip文件包含JSON文件中的Meta信息。问题是这些JSON文件中字符串中的Unicode字符以一种奇怪的方式转义。
下面是这样一个字符串的例子:"nejni\u00c5\u00be\u00c5\u00a1\u00c3\u00ad bod: 0 mnm Ben\u00c3\u00a1tky\n"
例如,当我尝试用JavaScript的JSON.parse()
解析字符串并打印出来时,我得到:"nejnižšà bod: 0 mnm Benátky\n"
虽然应当"nejnižší bod: 0 mnm Benátky\n"
我可以看到\u00c5\u00be
应该在某种程度上对应于ž
,但我不能找出一般模式。
到目前为止,我已经能够理解这些字符:
'\u00c2\u00b0' : '°',
'\u00c3\u0081' : 'Á',
'\u00c3\u00a1' : 'á',
'\u00c3\u0089' : 'É',
'\u00c3\u00a9' : 'é',
'\u00c3\u00ad' : 'í',
'\u00c3\u00ba' : 'ú',
'\u00c3\u00bd' : 'ý',
'\u00c4\u008c' : 'Č',
'\u00c4\u008d' : 'č',
'\u00c4\u008f' : 'ď',
'\u00c4\u009b' : 'ě',
'\u00c5\u0098' : 'Ř',
'\u00c5\u0099' : 'ř',
'\u00c5\u00a0' : 'Š',
'\u00c5\u00a1' : 'š',
'\u00c5\u00af' : 'ů',
'\u00c5\u00be' : 'ž',
那么这个奇怪的编码是什么呢?有没有已知的工具可以正确解码?
8条答案
按热度按时间t8e9dugd1#
编码是有效的UTF-8。问题是,JavaScript不使用UTF-8,它使用UTF-16。因此,您必须将有效的UTF-8转换为JavaScript UTF-16:
https://developer.mozilla.org/docs/Web/API/TextDecoder
uplii1fm2#
感谢Jen的精彩提问和Shawn的评论。
基本上,facebook似乎采用了unicode字符串表示的每个字节,然后导出为JSON,就好像这些字节是单独的Unicode码点一样。
我们需要做的是把每个六位数的最后两个字符(例如,
c3
from\u00c3
),将它们连接在一起并作为Unicode字符串读取。这就是我在Ruby中的做法(参见gist):
使用
bytes_re
,我们可以捕获所有错误的Unicode字符序列。然后,对于每个序列,将'\u00'替换为'\x'(例如,
\xc3
),在"
周围加上引号,并使用Ruby的内置字符串解析,以便将\xc3\xbe...
字符串转换为实际的字节,这些字节稍后将在JSON中保留为Unicode字符或由#to_json
方法正确引用。[1...-1]
用于删除#to_json
插入的引号我想解释代码,因为问题不是ruby特定的,读者可能会使用另一种语言。
我想有人可以用一个足够丑陋的
sed
命令来做这件事。wkftcu5l3#
您可以使用正则表达式查找几乎是unicode的字符组,将它们解码为Latin-1,然后再编码回UTF-8
下面的代码应该在python3.x中工作:
u4vypkhs4#
JSON文件本身是UTF-8,但字符串是UTF-16字符,转换为字节序列,然后使用转义序列转换为UTF-8。
这个命令在Emacs中修复了这样一个文件:
ct3nt3jp5#
只是添加了如何从“\u00c5\u0098”到“\”的一般规则。将\u部分的最后两个字母放在一起得到c5和98,这是utf-8表示的两个字节。UTF-8将代码点编码为两个字节,如下所示:110 xxxxx 10 xxxxxx,其中x是字符代码的实际位。你可以把这两个字节,用&来得到x的部分,把它们一个接一个地放在下一个后面,然后把它读成一个数字,你得到0x 158,这是'x'的代码。
我的JavaScript实现:
flvtvl506#
以防万一,如果有人正在寻找PHP解决方案;)
模式如下:“查找以
\u00
开头并继续到十六进制数字的内容”。然后将这些数字转换为相应的字节。mzsu5hc07#
如果有人正在寻找GO版本的代码,这里是:
}
fgw7neuy8#
对于python,有一个名为
unicode-escape
的编码,它将解析这些\u00xx
字符,所以你不需要使用正则表达式。此外,我们可以使用
latin-1
编码将其重新编码为纯8位二进制。这种编码是非常明显和天真的编码,它将字符串视为一系列8位字节。然后,当我们解码为UTF-8时,一切又正常了。