本文翻译自:Saving utf-8 texts in json.dumps as UTF8, not as \u escape sequence
sample code: 样例代码:
>>> import json
>>> json_string = json.dumps("ברי צקלה")
>>> print json_string
"\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4"
The problem: it's not human readable. 问题:这不是人类可读的。 My (smart) users want to verify or even edit text files with JSON dumps (and I'd rather not use XML). 我的(智能)用户想要使用JSON转储来验证甚至编辑文本文件(我宁愿不使用XML)。
Is there a way to serialize objects into UTF-8 JSON strings (instead of \\uXXXX
)? 有没有一种方法可以将对象序列化为UTF-8 JSON字符串(而不是\\uXXXX
)?
#1楼
参考:https://stackoom.com/question/1EwOd/将utf-文本保存在json-dumps中为UTF-而不是-u转义序列
#2楼
Use the ensure_ascii=False
switch to json.dumps()
, then encode the value to UTF-8 manually: 使用ensure_ascii=False
切换到json.dumps()
,然后将值手动编码为UTF-8:
>>> json_string = json.dumps("ברי צקלה", ensure_ascii=False).encode('utf8')
>>> json_string
b'"\xd7\x91\xd7\xa8\xd7\x99 \xd7\xa6\xd7\xa7\xd7\x9c\xd7\x94"'
>>> print(json_string.decode())
"ברי צקלה"
If you are writing to a file, just use json.dump()
and leave it to the file object to encode: 如果要写入文件,只需使用json.dump()
并将其留给文件对象进行编码:
with open('filename', 'w', encoding='utf8') as json_file:
json.dump("ברי צקלה", json_file, ensure_ascii=False)
Caveats for Python 2 Python 2警告
For Python 2, there are some more caveats to take into account. 对于Python 2,还有更多注意事项需要考虑。 If you are writing this to a file, you can use io.open()
instead of open()
to produce a file object that encodes Unicode values for you as you write, then use json.dump()
instead to write to that file: 如果要将其写入文件,则可以使用io.open()
而不是open()
来生成一个文件对象,该对象在编写时为您编码Unicode值,然后使用json.dump()
代替来写入该文件:
with io.open('filename', 'w', encoding='utf8') as json_file:
json.dump(u"ברי צקלה", json_file, ensure_ascii=False)
Do note that there is a bug in the json
module where the ensure_ascii=False
flag can produce a mix of unicode
and str
objects. 请注意, json
模块中存在一个bug,其中ensure_ascii=False
标志可以生成unicode
和str
对象的混合体。 The workaround for Python 2 then is: 那么,Python 2的解决方法是:
with io.open('filename', 'w', encoding='utf8') as json_file:
data = json.dumps(u"ברי צקלה", ensure_ascii=False)
# unicode(data) auto-decodes data to unicode if str
json_file.write(unicode(data))
In Python 2, when using byte strings (type str
), encoded to UTF-8, make sure to also set the encoding
keyword: 在Python 2中,当使用编码为UTF-8的字节字符串(类型str
)时,请确保还设置了encoding
关键字:
>>> d={ 1: "ברי צקלה", 2: u"ברי צקלה" }
>>> d
{1: '\xd7\x91\xd7\xa8\xd7\x99 \xd7\xa6\xd7\xa7\xd7\x9c\xd7\x94', 2: u'\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4'}
>>> s=json.dumps(d, ensure_ascii=False, encoding='utf8')
>>> s
u'{"1": "\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4", "2": "\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4"}'
>>> json.loads(s)['1']
u'\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4'
>>> json.loads(s)['2']
u'\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4'
>>> print json.loads(s)['1']
ברי צקלה
>>> print json.loads(s)['2']
ברי צקלה
#3楼
Using ensure_ascii=False in json.dumps is the right direction to solve this problem, as pointed out by Martijn. Martijn指出,在json.dumps中使用suresure_ascii = False是解决此问题的正确方向。 However, this may raise an exception: 但是,这可能会引发异常:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 1: ordinal not in range(128)
You need extra settings in either site.py or sitecustomize.py to set your sys.getdefaultencoding() correct. 您需要在site.py或sitecustomize.py中进行其他设置,才能正确设置sys.getdefaultencoding()。 site.py is under lib/python2.7/ and sitecustomize.py is under lib/python2.7/site-packages. site.py在lib / python2.7 /下,sitecustomize.py在lib / python2.7 / site-packages下。
If you want to use site.py, under def setencoding(): change the first if 0: to if 1: so that python will use your operation system's locale. 如果要使用site.py,请在def setencoding()下:将第一个if 0:更改为if 1 :,以便python使用操作系统的语言环境。
If you prefer to use sitecustomize.py, which may not exist if you haven't created it. 如果您喜欢使用sitecustomize.py,那么如果尚未创建,则可能不存在。 simply put these lines: 只需将这些行:
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
Then you can do some Chinese json output in utf-8 format, such as: 然后,您可以以utf-8格式进行中文json输出,例如:
name = {"last_name": u"王"}
json.dumps(name, ensure_ascii=False)
You will get an utf-8 encoded string, rather than \\u escaped json string. 您将获得一个utf-8编码的字符串,而不是\\ u转义的json字符串。
To verify your default encoding: 验证默认编码:
print sys.getdefaultencoding()
You should get "utf-8" or "UTF-8" to verify your site.py or sitecustomize.py settings. 您应该获得“ utf-8”或“ UTF-8”来验证site.py或sitecustomize.py设置。
Please note that you could not do sys.setdefaultencoding("utf-8") at interactive python console. 请注意,您无法在交互式python控制台上执行sys.setdefaultencoding(“ utf-8”)。
#4楼
UPDATE: This is wrong answer, but it's still useful to understand why it's wrong. 更新:这是错误的答案,但是了解为什么它仍然是有用的。 See comments. 看评论。
How about unicode-escape
? unicode-escape
怎么样?
>>> d = {1: "ברי צקלה", 2: u"ברי צקלה"}
>>> json_str = json.dumps(d).decode('unicode-escape').encode('utf8')
>>> print json_str
{"1": "ברי צקלה", "2": "ברי צקלה"}
#5楼
Peters' python 2 workaround fails on an edge case: Peters的python 2解决方法在边缘情况下失败:
d = {u'keyword': u'bad credit \xe7redit cards'}
with io.open('filename', 'w', encoding='utf8') as json_file:
data = json.dumps(d, ensure_ascii=False).decode('utf8')
try:
json_file.write(data)
except TypeError:
# Decode data to Unicode first
json_file.write(data.decode('utf8'))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe7' in position 25: ordinal not in range(128)
It was crashing on the .decode('utf8') part of line 3. I fixed the problem by making the program much simpler by avoiding that step as well as the special casing of ascii: 它在第3行的.decode('utf8')部分崩溃。我通过避免该步骤以及ascii的特殊大小写,使程序更加简单,从而解决了该问题:
with io.open('filename', 'w', encoding='utf8') as json_file:
data = json.dumps(d, ensure_ascii=False, encoding='utf8')
json_file.write(unicode(data))
cat filename
{"keyword": "bad credit çredit cards"}
#6楼
Here's my solution using json.dump(): 这是我使用json.dump()的解决方案:
def jsonWrite(p, pyobj, ensure_ascii=False, encoding=SYSTEM_ENCODING, **kwargs):
with codecs.open(p, 'wb', 'utf_8') as fileobj:
json.dump(pyobj, fileobj, ensure_ascii=ensure_ascii,encoding=encoding, **kwargs)
where SYSTEM_ENCODING is set to: 其中SYSTEM_ENCODING设置为:
locale.setlocale(locale.LC_ALL, '')
SYSTEM_ENCODING = locale.getlocale()[1]