为什么json.dumps使用“\uxxx”转义非科学字符

2024-09-27 07:24:42 发布

您现在位置:Python中文网/ 问答频道 /正文

在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'

Tags: 函数字符串jsonstring字节asciiunicode字符
3条回答

Why does json.dumps escape non-ascii characters with “\uxxxx”

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服务的默认值,sshcron),即使在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字符:

>>> import json
>>> json.loads(r'"\u0061"')
u'a'
>>> json.loads('"a"')
u'a'

不要把它与Python中的转义混淆,Python中的字符串文本用于源代码。u"\u00f8"是一个Unicode字符,但是"\u00f8"在输出中是八个字符(在Python源代码中,可以将其改为r'"\u00f8"' == '"\\u00f8"' == u'"\\u00f8"'(反斜杠在Python文本和json文本中都是特殊的,可能会发生双转义)。JSON中也没有\x转义:

>>> 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"'

The output of json.dumps() is a str, which is a byte string in Python 2. And thus shouldn't it escape characters as \xhh ?

json.dumps(obj, ensure_ascii=True)只生成可打印的ascii字符,因此print repr(json.dumps(u"\xf8"))将不包含用于表示(repr())不可打印字符(字节)的\xhh转义。

\u即使对于仅限ascii的输入,也可能需要转义:

#!/usr/bin/env python2
import json
print json.dumps(map(unichr, range(128)))

输出

["\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"]

But isn't this quite confusing because \uxxxx is a unicode character and should be used inside a unicode string

\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。

演示:

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 2u"\u00f8"字符串中。也要注意他的其他言论!

相关问题 更多 >

    热门问题