Je sauve des textes utf-8 dans json.décharge en UTF8, pas en u séquence d'échappement

code échantillon:

>>> import json
>>> json_string = json.dumps("ברי צקלה")
>>> print json_string
"u05d1u05e8u05d9 u05e6u05e7u05dcu05d4"

le problème: il n'est pas lisible par les humains. Mes utilisateurs (intelligents) veulent vérifier ou même éditer des fichiers texte avec JSON dumps. (et je préfère ne pas l'utiliser XML)

y a-t-il un moyen de sérialiser les objets en chaîne utf-8 json (au lieu de uXXXX ) ?

ce n'aide pas:

>>> output = json_string.decode('string-escape')
"u05d1u05e8u05d9 u05e6u05e7u05dcu05d4"

ce fonctionne, mais si l'un des sous-objets est un python-unicode et non utf-8, il va de vidage de la poubelle:

>>> #### ok:
>>> s= json.dumps( "ברי צקלה", ensure_ascii=False)    
>>> print json.loads(s)   
ברי צקלה

>>> #### NOT ok:
>>> d={ 1: "ברי צקלה", 2: u"ברי צקלה" }
>>> print d
{1: 'xd7x91xd7xa8xd7x99 xd7xa6xd7xa7xd7x9cxd7x94', 
 2: u'xd7x91xd7xa8xd7x99 xd7xa6xd7xa7xd7x9cxd7x94'}
>>> s = json.dumps( d, ensure_ascii=False, encoding='utf8')
>>> print json.loads(s)['1']
ברי צקלה
>>> print json.loads(s)['2']
××¨× ×¦×§××
281
demandé sur Berry Tsakala 2013-08-20 18:18:18

8 réponses

utilisez le commutateur ensure_ascii=False pour json.dumps() , puis encodez la valeur à UTF-8 manuellement:

>>> json_string = json.dumps(u"ברי צקלה", ensure_ascii=False).encode('utf8')
>>> json_string
'"\xd7\x91\xd7\xa8\xd7\x99 \xd7\xa6\xd7\xa7\xd7\x9c\xd7\x94"'
>>> print json_string
"ברי צקלה"

si vous écrivez ceci à un fichier, vous pouvez utiliser io.open() au lieu de open() pour produire un objet de fichier qui Code des valeurs Unicode pour vous pendant que vous écrivez, puis utilisez json.dump() au lieu d'écrire à ce fichier:

with io.open('filename', 'w', encoding='utf8') as json_file:
    json.dump(u"ברי צקלה", json_file, ensure_ascii=False)

en Python 3, open() est un alias pour io.open() . Notez qu'il y a un bug dans le json module où le drapeau ensure_ascii=False peut produire un mix de unicode et str objets. La solution pour Python 2 est alors:

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))

si vous passez en byte strings (tapez str en Python 2, bytes en Python 3) encodé en UTF-8, assurez-vous de définir également le encoding mot-clé:

>>> 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']
ברי צקלה

notez que votre second échantillon est pas Unicode valide; vous lui avez donné UTF-8 octets comme un unicode littéral, qui serait jamais travail:

>>> s = u'\xd7\x91\xd7\xa8\xd7\x99 \xd7\xa6\xd7\xa7\xd7\x9c\xd7\x94'
>>> print s
××¨× ×¦×§××
>>> print s.encode('latin1').decode('utf8')
ברי צקלה

ce N'est que lorsque j'ai encodé cette chaîne en Latin 1 (dont les codépoints unicode mappent de un à un bytes) puis décodé en UTF-8 que vous voyez la sortie attendue. Cela n'a rien à voir avec JSON et tout à voir avec le fait que vous utilisez la mauvaise entrée. Le résultat est appelé un Mojibake .

si vous avez obtenu cette valeur Unicode à partir d'une chaîne littérale, elle a été décodée en utilisant le mauvais codec. Il se peut que votre terminal soit mal configuré, ou que votre éditeur de texte ait sauvegardé votre code source en utilisant un codec différent de celui avec lequel vous avez demandé à Python de lire le fichier. Ou vous l'avez trouvé dans une bibliothèque qui a appliqué le mauvais codec. tout cela n'a rien à voir avec la bibliothèque JSON .

377
répondu Martijn Pieters 2015-01-27 07:41:09

facile comme un gâteau

pour écrire dans un fichier

import codecs
import json

with codecs.open('your_file.txt', 'w', encoding='utf-8') as f:
    json.dump({"message":"xin chào việt nam"}, f, ensure_ascii=False)

à imprimer à stdin

import codecs
import json
print(json.dumps({"message":"xin chào việt nam"}, ensure_ascii=False))
38
répondu Trần Quang Hiệp 2016-11-15 00:27:46

mise à JOUR: C'est la mauvaise réponse, mais il est toujours utile de comprendre pourquoi c'est mal. Voir les commentaires.

et unicode-escape ?

>>> d = {1: "ברי צקלה", 2: u"ברי צקלה"}
>>> json_str = json.dumps(d).decode('unicode-escape').encode('utf8')
>>> print json_str
{"1": "ברי צקלה", "2": "ברי צקלה"}
25
répondu monitorius 2015-06-13 09:18:56

Peters " python 2 solution échoue sur un cas limite:

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)

il s'écrasait sur le .décoder ("utf8") une partie de la ligne 3. J'ai résolu le problème en rendant le programme beaucoup plus simple en évitant cette étape ainsi que le boîtier spécial de 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"}
22
répondu Jonathan Ray 2015-05-08 10:28:25

ce qui suit est ma compréhension var reading answer ci-dessus et google.

# coding:utf-8
r"""
@update: 2017-01-09 14:44:39
@explain: str, unicode, bytes in python2to3
    #python2 UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 7: ordinal not in range(128)
    #1.reload
    #importlib,sys
    #importlib.reload(sys)
    #sys.setdefaultencoding('utf-8') #python3 don't have this attribute.
    #not suggest even in python2 #see:/q/why-should-we-not-use-sys-setdefaultencoding-utf8-in-a-py-script-8846/".:$PYTHONPATH" python)
    #too complex
    #3.control by your own (best)
    #==> all string must be unicode like python3 (u'xx'|b'xx'.encode('utf-8')) (unicode 's disappeared in python3)
    #see: http://blog.ernest.me/post/python-setdefaultencoding-unicode-bytes

    #how to Saving utf-8 texts in json.dumps as UTF8, not as \u escape sequence
    #/q/saving-utf8-texts-in-json-dumps-as-utf8-not-as-u-escape-sequence-75651/"""

from __future__ import print_function
import json

a = {"b": u"中文"}  # add u for python2 compatibility
print('%r' % a)
print('%r' % json.dumps(a))
print('%r' % (json.dumps(a).encode('utf8')))
a = {"b": u"中文"}
print('%r' % json.dumps(a, ensure_ascii=False))
print('%r' % (json.dumps(a, ensure_ascii=False).encode('utf8')))
# print(a.encode('utf8')) #AttributeError: 'dict' object has no attribute 'encode'
print('')

# python2:bytes=str; python3:bytes
b = a['b'].encode('utf-8')
print('%r' % b)
print('%r' % b.decode("utf-8"))
print('')

# python2:unicode; python3:str=unicode
c = b.decode('utf-8')
print('%r' % c)
print('%r' % c.encode('utf-8'))
"""
#python2
{'b': u'\u4e2d\u6587'}
'{"b": "\u4e2d\u6587"}'
'{"b": "\u4e2d\u6587"}'
u'{"b": "\u4e2d\u6587"}'
'{"b": "\xe4\xb8\xad\xe6\x96\x87"}'

'\xe4\xb8\xad\xe6\x96\x87'
u'\u4e2d\u6587'

u'\u4e2d\u6587'
'\xe4\xb8\xad\xe6\x96\x87'

#python3
{'b': '中文'}
'{"b": "\u4e2d\u6587"}'
b'{"b": "\u4e2d\u6587"}'
'{"b": "中文"}'
b'{"b": "\xe4\xb8\xad\xe6\x96\x87"}'

b'\xe4\xb8\xad\xe6\x96\x87'
'中文'

'中文'
b'\xe4\xb8\xad\xe6\x96\x87'
"""
5
répondu Cheney 2017-01-09 07:06:06

voici ma solution en utilisant 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)

où SYSTEM_ENCODING est défini à:

locale.setlocale(locale.LC_ALL, '')
SYSTEM_ENCODING = locale.getlocale()[1]
4
répondu Neit Sabes 2016-08-26 09:56:06

utilisez codecs si possible,

with codecs.open('file_path', 'a+', 'utf-8') as fp:
    fp.write(json.dumps(res, ensure_ascii=False))
2
répondu Yulin GUO 2018-08-14 06:58:31

utilisant ensure_ascii=False dans json.dumps est la bonne direction pour résoudre ce problème, comme souligné par Martijn. Toutefois, cela peut soulever une exception:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 1: ordinal not in range(128)

vous avez besoin de paramètres supplémentaires dans l'un ou l'autre site.py ou sitecustomize.py pour configurer votre système.getdefaultencoding () correct. site.py est sous lib / python2.7 / et sitecustomize.py est sous lib / python2.7 / site-packages.

si vous voulez utiliser site.py, sous def setencoding(): change le d'abord si 0: à Si 1: pour que python utilise la locale de votre système d'exploitation.

si vous préférez utiliser sitecustomize.py, qui peut ne pas exister si vous ne l'avez pas créé. il suffit de mettre ces lignes:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

alors vous pouvez faire une sortie JSON chinoise au format utf-8, comme:

name = {"last_name": u"王"}
json.dumps(name, ensure_ascii=False)

vous obtiendrez une chaîne encodée utf-8, plutôt qu'une chaîne JSON \u échappée.

Pour vérifier votre encodage par défaut:

print sys.getdefaultencoding()

vous devriez obtenir "utf-8" ou "UTF-8" pour vérifier votre site.py ou sitecustomize.py paramètres.

s'il vous Plaît noter que vous ne pouvez pas faire sys.setdefaultencoding ("utf-8") sur la console Python interactive.

-3
répondu Ryan X 2014-01-05 02:25:35