Zapisywanie tekstów utf-8 w json.zrzuty jako UTF8, nie jako sekwencja ucieczki u

Przykładowy kod:

>>> import json
>>> json_string = json.dumps("ברי צקלה")
>>> print json_string
"\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4"
Problem: nie jest czytelny dla człowieka. Moi (inteligentni) użytkownicy chcą zweryfikować lub nawet edytować pliki tekstowe za pomocą zrzutów JSON. (i wolałbym nie używać XML)

Czy istnieje sposób serializacji obiektów do ciągu JSON utf-8 (zamiast \uXXXX)?

To nie pomaga:

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

To działa, ale Jeśli jakikolwiek obiekt podrzędny jest Pythonem-unicode, a nie utf-8, wyrzuci śmieci:

>>> #### 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']
××¨× ×¦×§××
Author: Berry Tsakala, 2013-08-20

8 answers

Użyj przełącznika ensure_ascii=False na json.dumps(), a następnie ręcznie Zakoduj wartość do UTF-8:

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

Jeśli zapisujesz to do pliku, możesz użyć io.open() zamiast open() stworzyć obiekt file, który koduje wartości Unicode podczas zapisu, użyj zamiast tego json.dump() do zapisu do tego pliku:

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

W Pythonie 3, wbudowany open() jest aliasem dla io.open(). Należy pamiętać, że istnieje błąd w module json , gdzie znacznik ensure_ascii=False może wytworzyć mix Z unicode i str obiektów. Obejście problemu dla Pythona 2 to:

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

Jeśli przekazujesz ciągi bajtów (wpisz str w Pythonie 2, bytes w Pythonie 3) zakodowane do UTF-8, upewnij się, że ustawisz również słowo kluczowe 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']
ברי צקלה

Zauważ, że twoja druga próbka to , a nie poprawny Unicode; podałeś mu UTF-8 bajtów jako literał unicode, który nigdy nie zadziała:

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

Tylko wtedy, gdy zakodowałem ten ciąg do Latin 1 (którego Unicode codepoints map jeden do jednego bajtów) następnie dekoduj jako UTF-8 Czy widzisz oczekiwane wyjście. To nie ma nic wspólnego z JSONEM i z tym, że używasz niewłaściwego wejścia. Wynik nazywa się Mojibake.

Jeśli otrzymałeś tę wartość Unicode z literału łańcuchowego, została ona zdekodowana przy użyciu niewłaściwego kodeka. Być może twój terminal jest źle skonfigurowany lub edytor tekstu zapisał kod źródłowy za pomocą innego kodeka niż ten, za pomocą którego kazałeś Pythonowi przeczytać plik. Albo ty go pozyskałeś z biblioteki, która zastosowała niewłaściwy kodek. To wszystko nie ma nic wspólnego z biblioteką JSON.

 377
Author: Martijn Pieters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-27 07:41:09

Łatwe jak ciasto

Aby zapisać do pliku

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)

Aby wydrukować na stdin

import codecs
import json
print(json.dumps({"message":"xin chào việt nam"}, ensure_ascii=False))
 38
Author: Trần Quang Hiệp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-15 00:27:46

Aktualizacja: to zła odpowiedź, ale nadal warto zrozumieć, dlaczego jest zła. Zobacz komentarze.

A może unicode-escape?

>>> d = {1: "ברי צקלה", 2: u"ברי צקלה"}
>>> json_str = json.dumps(d).decode('unicode-escape').encode('utf8')
>>> print json_str
{"1": "ברי צקלה", "2": "ברי צקלה"}
 25
Author: monitorius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-13 09:18:56

Obejście Pythona 2 Petersa nie powiodło się w przypadku 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)
Rozbijał się o ...decode ('utf8') część linii 3. Naprawiłem problem, upraszczając program, unikając tego kroku, a także specjalnej obudowy 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
Author: Jonathan Ray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-08 10:28:25

Poniżej znajduje się moje zrozumienie var czytając odpowiedź powyżej i 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'
"""
 5
Author: Cheney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-09 07:06:06

Oto moje rozwiązanie przy użyciu 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)

Gdzie SYSTEM_ENCODING jest ustawiony na:

locale.setlocale(locale.LC_ALL, '')
SYSTEM_ENCODING = locale.getlocale()[1]
 4
Author: Neit Sabes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-26 09:56:06

Użyj kodeków, jeśli to możliwe,

with codecs.open('file_path', 'a+', 'utf-8') as fp:
    fp.write(json.dumps(res, ensure_ascii=False))
 2
Author: Yulin GUO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-14 06:58:31

Używanie ensure_ascii = False w json.dumps jest właściwym kierunkiem rozwiązania tego problemu, jak wskazał Martijn. Jednak może to spowodować wyjątek:

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

Potrzebne są dodatkowe ustawienia w site.py lub sitecustomize.py aby ustawić swój sys.getdefaultencoding () poprawne. site.py jest pod lib / python2. 7 / i sitecustomize.py jest pod lib / python2.7 / site-packages.

Jeśli chcesz użyć site.py, pod def setencoding (): Zmień pierwsze if 0: Na if 1: tak aby python używał Twojego lokalizacja systemu operacyjnego.

Jeśli wolisz używać sitecustomize.py, który może nie istnieć, jeśli go nie stworzyłeś. po prostu te linie:

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

Następnie możesz wykonać niektóre chińskie wyjście json w formacie utf-8, takie jak:

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

Otrzymasz kodowany łańcuch utf-8, zamiast \ u \ u000f \ u000f \ u000f \ u000f \ u000f.

Aby zweryfikować domyślne kodowanie:

print sys.getdefaultencoding()

Powinieneś uzyskać "utf-8" lub "UTF-8", aby zweryfikować swoje site.py lub sitecustomize.py ustawienia.

Uwaga tego nie mogłeś zrobić.setdefaultencoding ("utf-8") w interaktywnej konsoli Pythona.

 -3
Author: Ryan X,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-05 02:25:35