python with Salvando utf-8 textos em json.dumps como UTF8, não como \ u seqüência de escape




python load json encoding (8)

Código de amostra:

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

O problema: não é legível para humanos. Meus usuários (inteligentes) querem verificar ou até mesmo editar arquivos de texto com dumps JSON. (e prefiro não usar XML)

Existe uma maneira de serializar objetos na string utf-8 json (em vez de \ uXXXX)?

isso não ajuda:

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

isto funciona, mas se algum sub-objeto é um python-unicode e não utf-8, ele despeja lixo:

>>> #### 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']
××¨× ×¦×§××

Aqui está minha solução usando 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)

onde SYSTEM_ENCODING está definido como:

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

A solução alternativa de Python 2 de Peters falha em um caso de borda:

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)

Ele estava travando na parte do código. ('Utf8') da linha 3. Eu consertei o problema, tornando o programa muito mais simples, evitando essa etapa, bem como o invólucro especial do 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"}

Use codecs se possível,

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

O seguinte é o meu entendimento var resposta leitura acima e 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://.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://.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'
"""

fácil como um bolo

Para gravar em um arquivo

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)

Para imprimir para stdin

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

ATUALIZAÇÃO: Esta é uma resposta errada, mas ainda é útil entender por que isso está errado. Ver comentários.

Como sobre unicode-escape ?

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

Usando ensure_ascii = False em json.dumps é a direção certa para resolver este problema, como apontado por Martijn. No entanto, isso pode levantar uma exceção:

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

Você precisa de configurações extras em site.py ou sitecustomize.py para definir o seu sys.getdefaultencoding () correto. site.py está sob lib / python2.7 / e sitecustomize.py está em lib / python2.7 / site-packages.

Se você quiser usar site.py, sob def setencoding (): mude o primeiro se 0: para if 1: de modo que o python use a localidade do seu sistema operacional.

Se preferir usar o sitecustomize.py, que pode não existir se você não o criou. basta colocar estas linhas:

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

Então você pode fazer algumas saídas json chinesas no formato utf-8, como:

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

Você receberá uma string codificada utf-8, em vez de uma string json com escape.

Para verificar sua codificação padrão:

print sys.getdefaultencoding()

Você deve obter "utf-8" ou "UTF-8" para verificar suas configurações de site.py ou sitecustomize.py.

Por favor, note que você não poderia fazer sys.setdefaultencoding ("utf-8") no console python interativo.


A partir do Python 3.7, o seguinte código funciona bem:

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

Saída:

{"symbol": "ƒ"}