python json.dumps 中文编码
一、
json.dumps(var,ensure_ascii=False)并不能解决中文乱码的问题
python 2.7版本
# -*- coding: utf-8 -*- m = {'a' : '你好'} print m =>{'a': '\xe4\xbd\xa0\xe5\xa5\xbd'} print json.dumps(m) =>{"a": "\u4f60\u597d"} print json.dumps(m,ensure_ascii=False) =>{"a": "\xe4\xbd\xa0\xe5\xa5\xbd"} print json.dumps(m,ensure_ascii=False).decode('utf8').encode('gb2312') =>{"a": "你好"}
最近接触python,遇到这个问题,上网查资料,基本上都是说json.dumps(var,ensure_ascii=False)可以解决中文编码问题,然而并没有。
要解决中文编码,需要知道python2.7对字符串是怎么处理的:
-
由于# -- coding: utf-8 -- 的作用,文件内容以utf-8编码,所以print m
输出的是utf-8编码后的结果{‘a’: ‘\xe4\xbd\xa0\xe5\xa5\xbd’} -
json.dumps 序列化时对中文默认使用的ascii编码, print json.dumps(m)输出unicode编码的结果
-
print json.dumps(m,ensure_ascii=False)不使用的ascii编码,以gbk编码
‘你好’ 用utf8编码是 %E4%BD%A0%E5%A5%BD 用gbk解码是 浣犲ソ -
字符串在Python内部的表示是unicode编码。
-
因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。
-
decode的作用是将其他编码的字符串转换成unicode编码
decode(’utf-8’)表示将utf-8编码的字符串转换成unicode编码。
-
encode的作用是将unicode编码转换成其他编码的字符串
encode(‘gb2312’),表示将unicode编码的字符串转换成gb2312编码。
-
python3中没有这种问题,所以最简单的方法是引入
__future__模块,把新版本的特性导入到当前版本from __future__ import unicode_literals print json.dumps(m,ensure_ascii=False) =>{"a": "你好"}
在写入文件的时候出现了Python2.7的UnicodeEncodeError: ‘ascii’ codec can’t encode异常错误 大神的解决方法: 不使用open打开文件,而使用codecs:from __future__ import unicode_literals import codecs fp = codecs.open('output.txt', 'a+', 'utf-8') fp.write(json.dumps(m,ensure_ascii=False)) fp.close()
二、
我们知道,python中的字符串分普通字符串和unicode字符串,一般从数据库中读取的字符串会自动被转换为unicode字符串
下面回到重点,使用json.dumps时,一般的用法为:
>>> obj={"name":"测试"}
>>> json.dumps(obj)
'{"name": "\\u6d4b\\u8bd5"}'
>>> print json.dumps(obj)
{"name": "\u6d4b\u8bd5"}
>>> json.dumps(obj).encode("utf-8")
'{"name": "\\u6d4b\\u8bd5"}'
可以看到这里输出的字符串为普通字符串,但是里面的内容却是unicode字符串的内容,即使对结果进行encode("utf-8") ,因为这个字符串本身就已经编码过了,所有进行encode不会有变化
要想得到字符串的真实表示,需要用到参数ensure_ascii=False(默认为True):
>>> json.dumps(obj,ensure_ascii=False) '{"name": "\xe6\xb5\x8b\xe8\xaf\x95"}' >>> print json.dumps(obj,ensure_ascii=False) {"name": "测试"}
坑:试试下面的用法(比如key是从数据库中读取的,则会以unicode字符串形式存在):
>>> key=u"name" >>> obj={key:"测试"} >>> json.dumps(obj,ensure_ascii=False) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib64/python2.6/json/__init__.py", line 237, in dumps **kw).encode(obj) File "/usr/lib64/python2.6/json/encoder.py", line 368, in encode return ''.join(chunks) UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 1: ordinal not in range(128)
个人认为:unicode编码和utf8编码混用,很容易引起这种错误!!!
这是因为key和value不能以混合普通字符串和unicode字符串的形式存在
改成下面则正常了(同时为普通字符串或同时为unicode字符串)
>>> key=u"name" >>> obj={key:u"测试"} >>> json.dumps(obj,ensure_ascii=False) u'{"name": "\u6d4b\u8bd5"}' >>> obj={key.encode("utf-8"):u"测试".encode("utf-8")} >>> json.dumps(obj,ensure_ascii=False) '{"name": "\xe6\xb5\x8b\xe8\xaf\x95"}'
另外说说还有一个参数default
考虑下面的场景:
>>> class Data: ... def __init__(self): ... self.name = "" ... self.detail = "" ... >>> data=Data() >>> data.name="名字" >>> data.detail="细节" >>> obj={"data":data} >>> json.dumps(obj,ensure_ascii=False)
会报下面的异常:
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib64/python2.6/json/__init__.py", line 237, in dumps **kw).encode(obj) File "/usr/lib64/python2.6/json/encoder.py", line 367, in encode chunks = list(self.iterencode(o)) File "/usr/lib64/python2.6/json/encoder.py", line 309, in _iterencode for chunk in self._iterencode_dict(o, markers): File "/usr/lib64/python2.6/json/encoder.py", line 275, in _iterencode_dict for chunk in self._iterencode(value, markers): File "/usr/lib64/python2.6/json/encoder.py", line 317, in _iterencode for chunk in self._iterencode_default(o, markers): File "/usr/lib64/python2.6/json/encoder.py", line 323, in _iterencode_default newobj = self.default(o) File "/usr/lib64/python2.6/json/encoder.py", line 344, in default raise TypeError(repr(o) + " is not JSON serializable") TypeError: <__main__.Data instance at 0x11e87e8> is not JSON serializable
这是因为json.dumps不知道如何对Data对象进行序列化,需要定义一个函数,并赋给参数default:
>>> def convert_to_builtin_type(obj): ... d = {} ... d.update(obj.__dict__) ... return d ... >>> json.dumps(obj,ensure_ascii=False, default=convert_to_builtin_type) '{"data": {"name": "\xe5\x90\x8d\xe5\xad\x97", "detail": "\xe7\xbb\x86\xe8\x8a\x82"}}' >>> print json.dumps(obj,ensure_ascii=False, default=convert_to_builtin_type) {"data": {"name": "名字", "detail": "细节"}}
utf8中文:unicode中文
posted on 2018-03-28 15:05 myworldworld 阅读(2530) 评论(0) 收藏 举报
浙公网安备 33010602011771号