web-dev-qa-db-fra.com

Enregistrer des textes utf-8 dans json.dumps en tant que UTF8, et non en tant que séquence d'échappement

exemple de code:

>>> import json
>>> json_string = json.dumps("ברי צקלה")
>>> print json_string
"\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4"

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

Existe-t-il un moyen de sérialiser des objets dans la chaîne utf-8 json (au lieu de\uXXXX)?

cela n'aide pas:

>>> output = json_string.decode('string-escape')
"\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4"

this fonctionne, mais si l'un des sous-objets est un python-unicode et pas utf-8, il va vider les ordures:

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

>>> #### NOT ok:
>>> d={ 1: "ברי צקלה", 2: u"ברי צקלה" }
>>> print d
{1: '\xd7\x91\xd7\xa8\xd7\x99 \xd7\xa6\xd7\xa7\xd7\x9c\xd7\x94', 
 2: u'\xd7\x91\xd7\xa8\xd7\x99 \xd7\xa6\xd7\xa7\xd7\x9c\xd7\x94'}
>>> s = json.dumps( d, ensure_ascii=False, encoding='utf8')
>>> print json.loads(s)['1']
ברי צקלה
>>> print json.loads(s)['2']
××¨× ×¦×§××
340
Berry Tsakala

Utilisez le commutateur ensure_ascii=False sur json.dumps(), puis codez la valeur en 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 dans un fichier, vous pouvez utiliser io.open() au lieu de open() pour générer un objet fichier qui code pour les valeurs Unicode lorsque vous écrivez, puis utiliser json.dump() pour écrire dans ce fichier:

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

En Python 3, la open() intégrée est un alias pour io.open(). Notez qu'il existe un bogue dans le module json où l'indicateur ensure_ascii=False peut produire un mélange d'objets unicode et str. La solution de contournement pour Python 2 est alors la suivante:

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 des chaînes d'octets (tapez str en Python 2, bytes en Python 3) codé en UTF-8, veillez à définir également le mot clé 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']
ברי צקלה

Notez que votre deuxième échantillon est pas valide Unicode; vous lui avez donné les octets UTF-8 sous forme de littéral unicode, qui ne fonctionnerait jamais :

>>> 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 points de code unicode mappent un à un en octets) puis décodé en UTF-8 que vous voyez la sortie attendue. Cela n'a rien à voir avec JSON et tout ce que vous utilisez est une mauvaise entrée. Le résultat s'appelle un Mojibake .

Si vous avez obtenu cette valeur Unicode à partir d'un littéral, il a été décodé à l'aide du mauvais codec. Il se peut que votre terminal soit mal configuré ou que votre éditeur de texte ait enregistré 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 obtenue d'une bibliothèque qui a appliqué le mauvais codec. Tout cela n'a rien à voir avec la bibliothèque JSON .

461
Martijn Pieters

É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 sur stdin

import codecs
import json
print(json.dumps({"message":"xin chào việt nam"}, ensure_ascii=False))
51

UPDATE: C'est une mauvaise réponse, mais il est toujours utile de comprendre pourquoi c'est faux. Voir les commentaires.

Que diriez-vous de unicode-escape?

>>> d = {1: "ברי צקלה", 2: u"ברי צקלה"}
>>> json_str = json.dumps(d).decode('unicode-escape').encode('utf8')
>>> print json_str
{"1": "ברי צקלה", "2": "ברי צקלה"}
27
monitorius

La solution de contournement de Peters 2 dans Python échoue sur un cas Edge:

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 se bloquait sur la partie .decode ('utf8') de la ligne 3. J'ai résolu le problème en simplifiant beaucoup le programme 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"}
24
Jonathan Ray

Ce qui suit est ma compréhension var lecture réponse 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:http://stackoverflow.com/questions/3828723/why-should-we-not-use-sys-setdefaultencodingutf-8-in-a-py-script
    #2.overwrite /usr/lib/python2.7/sitecustomize.py or (sitecustomize.py and PYTHONPATH=".:$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
    #http://stackoverflow.com/questions/18337407/saving-utf-8-texts-in-json-dumps-as-utf8-not-as-u-escape-sequence
"""

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

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 sur:

locale.setlocale(locale.LC_ALL, '')
SYSTEM_ENCODING = locale.getlocale()[1]
5
Neit Sabes

Depuis Python 3.7, le code suivant fonctionne bien:

from json import dumps
result = {"symbol": "ƒ"}
json_string = dumps(result, sort_keys=True, indent=2, ensure_ascii=False)
print(json_string)

Sortie:

{"symbol": "ƒ"}
3
Nik

Utilisez des codecs si possible,

with codecs.open('file_path', 'a+', 'utf-8') as fp:
    fp.write(json.dumps(res, ensure_ascii=False))
3
Yulin GUO

Si vous chargez une chaîne JSON à partir d'un fichier, le texte arabe en contient. Alors cela fonctionnera.

Supposer un fichier comme: arabic.json

{ 
"key1" : "لمستخدمين",
"key2" : "إضافة مستخدم"
}

Obtenez le contenu arabe du fichier arabic.json

with open(arabic.json, encoding='utf-8') as f:
   # deserialises it
   json_data = json.load(f)
   fh.close()


# json formatted string
json_data2 = json.dumps(json_data, ensure_ascii = False)

Pour utiliser les données JSON dans Django Modèle, procédez comme suit:

# If have to get the JSON index in Django Template file, then simply decode the encoded string.

json.JSONDecoder().decode(json_data2)

terminé! Nous pouvons maintenant obtenir les résultats sous forme d’index JSON avec une valeur arabe.

0
Chandan Sharma