显示带有非 ascii 字符的原始 JSON

Display raw JSON with non-ascii characters

我在终端中使用 Python3 显示原始 JSON 数据时遇到问题。我得到 json 作为来自 urllib 的响应:

r = urlopen(request)
response = r.read()

结果是一个字节串 b"...",其中一部分包含非 ASCII 字符,如 b"Chybn\u00e9 heslo",这应该给我这个 "Chybné heslo".

但我不知道如何解码它以显示 "Chybné heslo",如果我这样做:

print(b"Chybn\u00e9 heslo".decode('utf-8'))

我刚刚得到 "Chybn\u00e9 heslo"。我在这里做错了什么?

使用unicode-escape编解码器:

byte_str = b"Chybn\u00e9 heslo"
print(byte_str.decode('unicode-escape')) # Chybné heslo

你的问题的原因是字节串 \u00e9 不是 unicode 代码点。
这只是一个字节序列:

>>> len(b'\u00e9') # whereas len('\u00e9') == 1
6 

>>> [b for b in b'\u00e9']
[92, 117, 48, 48, 101, 57]

这些字节也是UTF-8字节,所以当你用这种编码解码它们时,你会得到相应的字符序列:

>>> b'\u00e9'.decode('utf-8')
'\u00e9'

>>> [chr(b) for b in b'\u00e9'] # decoding in 'byte-by-byte' mode
['\', 'u', '0', '0', 'e', '9']

另请注意,\\ 在某些字符串中是等效的(有关更多信息,请查看 this)。
例如:

>>> b'\u' == b'\u'
True
>>> b'\u00e9' == b'\u00e9'
True
>>> b'\n' == b'\n'
False

>>> '\u00e9' == '\u00e9'
False

>>> '\z' == '\z' 
True

如果它真的是一个有效的 JSON 字符串响应,它应该在字符串周围加上双引号,并且在这种情况下是一个完全 ASCII 响应,其 Unicode 代码点表示为 JSON 转义码。您可以使用 json 模块对其进行解码。这也将处理更复杂的 JSON 响应,包含列表和 key/value 对:

>>> import json
>>> json.loads(b'"Chybn\u00e9 heslo"')
'Chybné heslo'

同时查看 requests 模块(第 3 方),它将为您解码 JSON:

>>> import requests
>>> r = requests.get('http://date.jsontest.com')
>>> r.text
'{\n   "time": "06:58:22 AM",\n   "milliseconds_since_epoch": 1508914702539,\n   "date": "10-25-2017"\n}\n'
>>> r.json()
{'time': '06:58:22 AM', 'milliseconds_since_epoch': 1508914702539, 'date': '10-25-2017'}
>>> D = r.json()
>>> D['time']
'06:58:22 AM'