为什么json.dumps使用“\ uxxxx”转义非ascii字符

时间:2015-09-05 10:21:30

标签: python json unicode python-2.x

在Python 2中,函数json.dumps()将确保所有非ascii字符都转义为\uxxxx

Python 2 Json

但这不是很混乱,因为\uxxxx是一个unicode字符,应该在unicode字符串中使用。

json.dumps()的输出是str,它是Python 2中的字节字符串。因此它不应该将字符转义为\xhh

>>> unicode_string = u"\u00f8"
>>> print unicode_string
ø
>>> print json.dumps(unicode_string)
"\u00f8"
>>> unicode_string.encode("utf8")
'\xc3\xb8'

3 个答案:

答案 0 :(得分:5)

  

为什么json.dumps使用“\ uxxxx”

转义非ascii字符

Python 2可以将ascii-only字符串和Unicode字符串混合在一起。

这可能是一个不成熟的优化。如果Unicode字符串在Python 2中包含大多数ASCII范围内的字符,则它们可能需要比相应字节串多2-4倍的内存。

此外,即使在今天,print(unicode_string)在打印到Windows控制台时包含非ascii字符也可能很容易失败,除非安装了win-unicode-console Python包。即使在Unix上,如果使用C / POSIX语言环境(默认为init.d服务,sshcron在许多情况下),这可能会失败(这意味着ascii字符编码。有{{1但它并不总是可用,你必须明确配置它)。这可能解释了为什么在某些情况下您可能需要C.UTF-8

JSON格式是为Unicode文本定义的,因此严格来说ensure_ascii=True应始终返回一个Unicode字符串,但如果所有字符都在ASCII范围内(json.dumps()具有类似的“优化”),它可能会返回一个字节串。令人困惑的是,Python 2允许在某些情况下将ascii-only字符串视为Unicode字符串(允许隐式转换)。 Python 3更严格(禁止隐式转换)。

可以使用仅ASCII字节串而不是Unicode字符串(可能使用非ASCII字符)来节省内存和/或提高Python 2中的互操作性。

要停用该行为,请使用xml.etree.ElementTree

重要的是避免将Unicode字符串与Python源代码中的表示混淆为Python字符串文字或将其在文件中表示为JSON文本。

JSON格式允许转义任何字符,而不仅仅是ASCII范围之外的Unicode字符:

json.dumps(obj, ensure_ascii=False)

不要将它与Python 源代码中使用的Python字符串文字中的转义混淆。 >>> import json >>> json.loads(r'"\u0061"') u'a' >>> json.loads('"a"') u'a' 是一个 Unicode字符,但输出中的u"\u00f8"八个字符(在Python 源代码中,你可以将其改为"\u00f8"(反斜杠在Python 文字和json文本中都是特殊的 - 双重转义可能会发生)。也没有{{1}在JSON中转义:

r'"\u00f8"' == '"\\u00f8"' == u'"\\u00f8"'
  

json.dumps()的输出是一个str,它是Python 2中的一个字节字符串。因此它不应该将字符转义为\ xhh?

\x仅生成可打印的ascii字符,因此>>> json.loads(r'"\x61"') # invalid JSON Traceback (most recent call last): ... ValueError: Invalid \escape: line 1 column 2 (char 1) >>> r'"\x61"' # valid Python literal (6 characters) '"\\x61"' >>> '"\x61"' # valid Python literal with escape sequence (3 characters) '"a"' 将不包含使用表示json.dumps(obj, ensure_ascii=True))非的print repr(json.dumps(u"\xf8"))转义符-printable chars(bytes)。

即使对于仅支持ascii的输入,

\xhh转义也是必要的:

repr()

输出

\u
  

但这不是很混乱,因为\ uxxxx是一个unicode字符,应该在unicode字符串中使用

#!/usr/bin/env python2 import json print json.dumps(map(unichr, range(128))) 是6个字符,在某些上下文中可能被解释为单个字符,例如,在Python中,源代码["\u0000", "\u0001", "\u0002", "\u0003", "\u0004", "\u0005", "\u0006", "\u0007", "\b", "\t", "\n", "\u000b", "\f", "\r", "\u000e", "\u000f", "\u0010", "\u0011", "\u0012", "\u0013", "\u0014", "\u0015", "\u0016", "\u0017", "\u0018", "\u0019", "\u001a", "\u001b", "\u001c", "\u001d", "\u001e", "\u001f", " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "\u007f"] 是一个Python文字,在内存中创建一个带有单个字符串的Unicode字符串 Unicode字符。但是如果你在json文本中看到\uxxxx;它是六个字符,如果你加载它(u"\uxxxx"),代表一个Unicode字符。

此时,您应该了解\uxxxx

的原因

答案 1 :(得分:2)

\u中的"\u00f8"实际上并不是\x之类的转义序列。 \u是文字r'\u'。但是这样的字节字符串很容易转换为Unicode。

演示:

s = "\u00f8"
u = s.decode('unicode-escape')
print repr(s), len(s), repr(u), len(u)

s = "\u2122"
u = s.decode('unicode-escape')
print repr(s), len(s), repr(u), len(u)

<强>输出

'\\u00f8' 6 u'\xf8' 1
'\\u2122' 6 u'\u2122' 1

正如J.F.Sebastian在评论中提到的,Unicode字符串\u00f8内部是一个真正的转义码,即Python 3字符串或Python 2 u"\u00f8"字符串。还要留意他的其他言论!

答案 2 :(得分:1)

这正是重点。你得到一个字节串,而不是Unicode字符串。因此,需要转义Unicode字符才能生存。 JSON允许转义,因此提供了一种表示Unicode字符的安全方式。