在Python 2中,函数json.dumps()
将确保所有非ascii字符转义为\uxxxx
。
但这不是很混乱,因为\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'
Python 2可以将ascii-only-bytestrings和Unicode字符串混合在一起。
这可能是一个过早的优化。在Python 2中,如果Unicode字符串包含的字符大多在ASCII范围内,则它可能需要比相应的bytestring多2-4倍的内存。
另外,即使在今天,如果打印到Windows控制台时包含非ascii字符,则
print(unicode_string)
可能很容易失败,除非安装了类似win-unicode-console
的Python包。如果使用C/POSIX语言环境(在许多情况下,init.d
服务的默认值,ssh
,cron
),即使在Unix上也可能失败(这意味着使用ascii字符编码)。有C.UTF-8
但是它并不总是可用的,您必须显式地配置它)。这也许可以解释为什么在某些情况下您可能需要ensure_ascii=True
。JSON格式是为Unicode文本定义的,因此严格来说,
json.dumps()
应该始终返回Unicode字符串,但如果所有字符都在ASCII范围内(xml.etree.ElementTree
具有类似的“优化”),则它可能返回bytestring。Python 2允许在某些情况下(允许隐式转换)将ascii-only-bytestring视为Unicode字符串,这令人困惑。Python 3更严格(禁止隐式转换)。可以使用ASCII-only bytestrings代替Unicode字符串(可能有非ASCII字符)来节省内存和/或提高Python 2中的互操作性。
要禁用该行为,请使用
json.dumps(obj, ensure_ascii=False)
。避免将Unicode字符串与其在Python源代码中的表示形式混淆为Python字符串文本或将其在文件中的表示形式混淆为JSON文本是很重要的。
JSON格式允许转义任何字符,而不仅仅是ASCII范围之外的Unicode字符:
不要把它与Python中的转义混淆,Python中的字符串文本用于源代码。
u"\u00f8"
是一个单Unicode字符,但是"\u00f8"
在输出中是八个字符(在Python源代码中,可以将其改为r'"\u00f8"' == '"\\u00f8"' == u'"\\u00f8"'
(反斜杠在Python文本和json文本中都是特殊的,可能会发生双转义)。JSON中也没有\x
转义:json.dumps(obj, ensure_ascii=True)
只生成可打印的ascii字符,因此print repr(json.dumps(u"\xf8"))
将不包含用于表示(repr()
)不可打印字符(字节)的\xhh
转义。\u
即使对于仅限ascii的输入,也可能需要转义:输出
\uxxxx
是6个字符,在某些上下文(例如,在Python源代码中)中可以解释为单个字符u"\uxxxx"
是一个Python文本,它在内存中创建一个带有单个Unicode字符的Unicode字符串。但是,如果在json文本中看到\uxxxx
;如果加载单个Unicode字符(json.loads()
),则六个字符可能表示该字符。在这一点上,您应该理解为什么
len(json.loads('"\\\\"')) == 1
。这正是重点。返回一个字节字符串,而不是Unicode字符串。因此,需要对Unicode字符进行转义才能生存。JSON允许转义,因此提供了一种表示Unicode字符的安全方法。
"\u00f8"
中的\u
实际上不是像\x
那样的转义序列。\u
是一个文本r'\u'
。但是这样的字节字符串可以很容易地转换成Unicode。演示:
输出
正如J.F.Sebastian在评论中提到的,在Unicode字符串中,
\u00f8
是一个真正的转义代码,即在Python 3字符串或Python 2u"\u00f8"
字符串中。也要注意他的其他言论!相关问题 更多 >
编程相关推荐