从 Facebook 数据导出中解码看似格式错误的 Unicode 指针的 utf8 表示
Decode seemingly malformed utf8 representation of Unicode pointer from Facebook data export
类似于 , is there a way to decode some of the seemingly malformed UTF-8 data returned from downloading a copy of my Facebook data?
看一个特定的例子,在我的一个聊天中,我有一条仅包含表情符号的已发送消息。使用 vim
打开 message_1.json
文件并查看相应的条目会显示文本 "\u00f0\u009f\u0092\u008e"
。然而,这与我终端的视图不同 (Mac OSX)
$ jq '.messages[0].content' message_1.json
"ð" # Whosebug seems to be truncating this string, there are 3 extra chars which show as spaces
$ jq '.messages[0].content' message_1.json > utf
$ cat utf
"ð"
$ od -h utf
0000000 c322 c2b0 c29f c292 228e 000a
0000013
$ wc utf
1 1 11 utf
这也不同于直接将表情符号粘贴到文件中的输出
$ echo '' > gem.txt
$ cat gem.txt
$ od -h gem.txt
0000000 9ff0 8e92 000a
0000005
$ wc gem.txt
1 1 5 gem.txt
当我用 python3
读取这两个文件时,我得到了看似不同的信息
$ python3
Python 3.7.3 (default, Dec 13 2019, 19:58:14)
[Clang 11.0.0 (clang-1100.0.33.17)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> with open('gem.txt', 'r') as f:
... gem = f.read()
...
>>> gem
'\n'
>>> len(gem)
2
>>> ord(gem[0])
128142
>>>
>>>
>>> with open('utf', 'r') as f:
... utf = f.read()
...
>>> utf
'"ð\x9f\x92\x8e"\n'
>>> len(utf)
7
>>> for char in utf:
... print(ord(char))
...
34
240
159
146
142
34
10
>>>
我有几个基于此行为的问题:
- Facebook 返回的数据是否编码错误? This page 显示 gem 表情符号的正确 Unicode 指针为
U+1F48E
,相应的 UTF-8 0xF0 0x9F 0x92 0x8E
表示与 od
[ 的字节输出相匹配=37=]
- 有没有办法解析 Facebook 返回的字符串?貌似上个问题推荐先用正则表达式转换文本再做,这个是必须的吗?
gem.txt
长度为5个字节,减去换行符,4个字节表示表情符号。这对我来说很有意义,因为它的 UTF-8 表示需要 4 个字节。为什么 utf
文档列出 11 个字节(大概是 10 个没有换行符)?
看起来您的 JSON 文件的内容确实 mojibaked,即。用错误的编码误解了。
>>> import json
>>> # That's how it should look:
>>> print(json.dumps(''))
"\ud83d\udc8e"
>>> # That's what you got:
>>> mojibaked = ''.encode('utf8').decode('latin1')
>>> print(json.dumps(mojibaked))
"\u00f0\u009f\u0092\u008e"
检查您是否可以修复 JSON 文件的创建方式。
Latin-1 在某些 tools/protocols 中是默认值。
方便的是,您始终可以无一例外地将任何字节流解码为 Latin-1。
它可能会破坏你的输入,就像这里发生的那样。
如果您无法修复源代码,您可以通过反向进行编码往返来恢复:
>>> mojibaked = json.loads('"\u00f0\u009f\u0092\u008e"')
>>> mojibaked
'ð\x9f\x92\x8e'
>>> mojibaked.encode('latin1').decode('utf8')
''
类似于
看一个特定的例子,在我的一个聊天中,我有一条仅包含表情符号的已发送消息。使用 vim
打开 message_1.json
文件并查看相应的条目会显示文本 "\u00f0\u009f\u0092\u008e"
。然而,这与我终端的视图不同 (Mac OSX)
$ jq '.messages[0].content' message_1.json
"ð" # Whosebug seems to be truncating this string, there are 3 extra chars which show as spaces
$ jq '.messages[0].content' message_1.json > utf
$ cat utf
"ð"
$ od -h utf
0000000 c322 c2b0 c29f c292 228e 000a
0000013
$ wc utf
1 1 11 utf
这也不同于直接将表情符号粘贴到文件中的输出
$ echo '' > gem.txt
$ cat gem.txt
$ od -h gem.txt
0000000 9ff0 8e92 000a
0000005
$ wc gem.txt
1 1 5 gem.txt
当我用 python3
读取这两个文件时,我得到了看似不同的信息$ python3
Python 3.7.3 (default, Dec 13 2019, 19:58:14)
[Clang 11.0.0 (clang-1100.0.33.17)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> with open('gem.txt', 'r') as f:
... gem = f.read()
...
>>> gem
'\n'
>>> len(gem)
2
>>> ord(gem[0])
128142
>>>
>>>
>>> with open('utf', 'r') as f:
... utf = f.read()
...
>>> utf
'"ð\x9f\x92\x8e"\n'
>>> len(utf)
7
>>> for char in utf:
... print(ord(char))
...
34
240
159
146
142
34
10
>>>
我有几个基于此行为的问题:
- Facebook 返回的数据是否编码错误? This page 显示 gem 表情符号的正确 Unicode 指针为
U+1F48E
,相应的 UTF-80xF0 0x9F 0x92 0x8E
表示与od
[ 的字节输出相匹配=37=] - 有没有办法解析 Facebook 返回的字符串?貌似上个问题推荐先用正则表达式转换文本再做,这个是必须的吗?
gem.txt
长度为5个字节,减去换行符,4个字节表示表情符号。这对我来说很有意义,因为它的 UTF-8 表示需要 4 个字节。为什么utf
文档列出 11 个字节(大概是 10 个没有换行符)?
看起来您的 JSON 文件的内容确实 mojibaked,即。用错误的编码误解了。
>>> import json
>>> # That's how it should look:
>>> print(json.dumps(''))
"\ud83d\udc8e"
>>> # That's what you got:
>>> mojibaked = ''.encode('utf8').decode('latin1')
>>> print(json.dumps(mojibaked))
"\u00f0\u009f\u0092\u008e"
检查您是否可以修复 JSON 文件的创建方式。 Latin-1 在某些 tools/protocols 中是默认值。 方便的是,您始终可以无一例外地将任何字节流解码为 Latin-1。 它可能会破坏你的输入,就像这里发生的那样。
如果您无法修复源代码,您可以通过反向进行编码往返来恢复:
>>> mojibaked = json.loads('"\u00f0\u009f\u0092\u008e"')
>>> mojibaked
'ð\x9f\x92\x8e'
>>> mojibaked.encode('latin1').decode('utf8')
''