Speichern von utf-8-Texten in json.dumps als UTF8, nicht als Escape-Sequenz

474

Beispielcode:

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

Das Problem: Es ist nicht für Menschen lesbar. Meine (intelligenten) Benutzer möchten Textdateien mit JSON-Dumps überprüfen oder sogar bearbeiten (und ich möchte lieber kein XML verwenden).

Gibt es eine Möglichkeit, Objekte in UTF-8-JSON-Zeichenfolgen (anstelle von \uXXXX) zu serialisieren ?

Berry Tsakala
quelle
9
+ für ברי צקלה :)))
rubmz

Antworten:

642

Verwenden Sie den ensure_ascii=FalseSchalter json.dumps(), um den Wert manuell in UTF-8 zu codieren:

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

Wenn Sie in eine Datei schreiben, verwenden Sie sie einfach json.dump()und überlassen Sie sie dem zu codierenden Dateiobjekt:

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

Vorsichtsmaßnahmen für Python 2

Bei Python 2 sind einige weitere Einschränkungen zu beachten. Wenn Sie dies in eine Datei schreiben, können Sie io.open()stattdessen open()ein Dateiobjekt erstellen, das beim Schreiben Unicode-Werte für Sie codiert, und json.dump()stattdessen in diese Datei schreiben:

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

Beachten Sie, dass das jsonModul einen Fehler enthält, durch den das ensure_ascii=FalseFlag eine Mischung aus unicodeund strObjekten erzeugen kann . Die Problemumgehung für Python 2 lautet dann:

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

Stellen Sie in Python 2 bei Verwendung von Byte-Strings (Typ str), die in UTF-8 codiert sind, sicher, dass Sie auch das encodingSchlüsselwort festlegen :

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

In eine Datei schreiben

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)

Auf Standard drucken

import json
print(json.dumps({"message":"xin chào việt nam"}, ensure_ascii=False))
Trần Quang Hiệp
quelle
1
SyntaxError: Nicht-ASCII-Zeichen '\ xc3' in der Datei json-utf8.py in Zeile 5, aber keine Codierung deklariert; siehe python.org/dev/peps/pep-0263 für Details
Alex
Vielen Dank! Ich wusste nicht, dass es so einfach war. Sie müssen nur vorsichtig sein, wenn die Daten, die Sie in json konvertieren, nicht vertrauenswürdige Benutzereingaben sind.
Karim Sonbol
@Alex haben Sie herausgefunden, wie Sie dieses Problem vermeiden können?
Gabriel Fair
@ Gabriel ehrlich gesagt, ich erinnere mich nicht. Es war nicht so wichtig, einen Ausschnitt beiseite zu legen :(
Alex
Arbeitete nur für mich mit der codecsBibliothek. Vielen Dank!
igorkf
29

UPDATE: Dies ist eine falsche Antwort, aber es ist immer noch nützlich zu verstehen, warum es falsch ist. Zeige Kommentare.

Wie wäre es unicode-escape?

>>> d = {1: "ברי צקלה", 2: u"ברי צקלה"}
>>> json_str = json.dumps(d).decode('unicode-escape').encode('utf8')
>>> print json_str
{"1": "ברי צקלה", "2": "ברי צקלה"}
monitorius
quelle
9
unicode-escapeist nicht notwendig: Sie könnten json.dumps(d, ensure_ascii=False).encode('utf8')stattdessen verwenden. Und es kann nicht garantiert werden, dass json in allen Fällen genau die gleichen Regeln wie der unicode-escapeCodec in Python verwendet, dh das Ergebnis kann in einigen Eckfällen das gleiche sein oder auch nicht. Die Ablehnung ist für eine unnötige und möglicherweise falsche Konvertierung. Nicht verwandt: Funktioniert nur für utf8-Gebietsschemas oder wenn envvar hier utf8 angibt (stattdessen Unicode drucken). print json_strPYTHONIOENCODING
JFS
3
Ein weiteres Problem: Doppelte Anführungszeichen in Zeichenfolgenwerten verlieren ihr Escapezeichen, sodass die JSON-Ausgabe unterbrochen wird .
Martijn Pieters
Fehler in Python3: AttributeError: 'str' Objekt hat kein Attribut '
decode
1
Unicode-Escape funktioniert gut! Ich würde diese Antwort als richtig akzeptieren.
Arbeiter
@jfs Nein, json.dumps(d, ensure_ascii=False).encode('utf8')funktioniert zumindest für mich nicht. Ich bekomme UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position ...Fehler. Die unicode-escapeVariante funktioniert jedoch einwandfrei.
Turing getestet
24

Peters 'Python 2-Problemumgehung schlägt in einem Randfall fehl:

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)

Es stürzte im .decode ('utf8') Teil von Zeile 3 ab. Ich habe das Problem behoben, indem ich das Programm viel einfacher gemacht habe, indem ich diesen Schritt sowie das spezielle Gehäuse von ASCII vermieden habe:

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"}
Jonathan Ray
quelle
2
Der 'Randfall' war einfach ein dummer, ungetesteter Fehler von meiner Seite. Ihr unicode(data)Ansatz ist die bessere Option als die Ausnahmebehandlung. Beachten Sie, dass das encoding='utf8'Schlüsselwortargument nichts mit der Ausgabe zu tun hat, die json.dumps()erzeugt wird. Es wird zum Decodieren von strEingaben verwendet, die die Funktion empfängt.
Martijn Pieters
2
@MartijnPieters: oder einfacher: open('filename', 'wb').write(json.dumps(d, ensure_ascii=False).encode('utf8'))Es funktioniert, ob dumps(nur ASCII ) str oder Unicode-Objekt zurückgegeben wird.
JFS
@JFSebastian: Richtig, weil zuerst implizit str.encode('utf8') dekodiert wird . Aber auch unicode(data), wenn ein strObjekt gegeben ist. :-) Mit Using haben io.open()Sie jedoch mehr Optionen, einschließlich der Verwendung eines Codecs, der eine Stückliste schreibt, und Sie folgen den JSON-Daten mit etwas anderem.
Martijn Pieters
@MartijnPieters: .encode('utf8')-basierte Variante funktioniert sowohl mit Python 2 als auch mit Python 3 (der gleiche Code). In unicodePython 3 gibt es keine. Keine Beziehung: JSON-Dateien sollten keine Stückliste verwenden (obwohl ein bestätigender JSON-Parser möglicherweise die Stückliste ignoriert, siehe Fehler 3983 ).
JFS
Hinzufügen, encoding='utf8'um json.dumpsdas Problem zu lösen. PS Ich habe einen kyrillischen Text zu entleeren
Max L
8

Ab Python 3.7 funktioniert der folgende Code einwandfrei:

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

Ausgabe:

{"symbol": "ƒ"}
Nik
quelle
2
auch in Python 3.6 (gerade verifiziert).
Berry Tsakala
7

Das Folgende ist mein Verständnis var Leseantwort oben und 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'
"""
Cheney
quelle
5

Hier ist meine Lösung mit 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)

Dabei ist SYSTEM_ENCODING auf Folgendes festgelegt:

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

Verwenden Sie nach Möglichkeit Codecs.

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

Danke für die ursprüngliche Antwort hier. Mit Python 3 die folgende Codezeile:

print(json.dumps(result_dict,ensure_ascii=False))

war in Ordnung. Versuchen Sie, nicht zu viel Text in den Code zu schreiben, wenn dies nicht unbedingt erforderlich ist.

Dies ist möglicherweise gut genug für die Python-Konsole. Um einen Server zufrieden zu stellen, müssen Sie möglicherweise das Gebietsschema wie hier beschrieben festlegen (wenn es sich um Apache2 handelt). Http://blog.dscpl.com.au/2014/09/setting-lang-and-lcall-when-using .html

Installieren Sie im Grunde he_IL oder ein anderes Sprachgebietsschema auf Ubuntu und überprüfen Sie, ob es nicht installiert ist

locale -a 

Installieren Sie es dort, wo XX Ihre Sprache ist

sudo apt-get install language-pack-XX

Zum Beispiel:

sudo apt-get install language-pack-he

Fügen Sie den folgenden Text zu / etc / apache2 / envvrs hinzu

export LANG='he_IL.UTF-8'
export LC_ALL='he_IL.UTF-8'

Dann würden Sie hoffentlich keine Python-Fehler von Apache bekommen wie:

print (js) UnicodeEncodeError: Der Codec 'ascii' kann keine Zeichen an Position 41-45 codieren: Ordnungszahl nicht im Bereich (128)

Versuchen Sie auch in Apache, utf als Standardcodierung festzulegen, wie hier erläutert: Wie ändere ich die Standardcodierung
für Apache in UTF-8?

Tun Sie es frühzeitig, da das Debuggen von Apache-Fehlern schmerzhaft sein kann und Sie fälschlicherweise glauben können, dass es sich um Python handelt, was in dieser Situation möglicherweise nicht der Fall ist

sivi
quelle
1

Wenn Sie eine JSON-Zeichenfolge aus einer Datei und einem Dateiinhalt mit arabischen Texten laden. Dann wird das funktionieren.

Angenommen, Datei wie: arabic.json

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

Rufen Sie den arabischen Inhalt aus der Datei arabic.json ab

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


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

Führen Sie die folgenden Schritte aus, um JSON-Daten in der Django-Vorlage zu verwenden:

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

json.JSONDecoder().decode(json_data2)

erledigt! Jetzt können wir die Ergebnisse als JSON-Index mit arabischem Wert erhalten.

Chandan Sharma
quelle
fh.close() fhist nicht definiert.
AMC
IT ist jetzt korrigiert. Es wäref.close()
Chandan Sharma
0

Verwenden Sie Unicode-Escape, um das Problem zu lösen

>>>import json
>>>json_string = json.dumps("ברי צקלה")
>>>json_string.encode('ascii').decode('unicode-escape')
'"ברי צקלה"'

erklären

>>>s = '漢  χαν  хан'
>>>print('unicode: ' + s.encode('unicode-escape').decode('utf-8'))
unicode: \u6f22  \u03c7\u03b1\u03bd  \u0445\u0430\u043d

>>>u = s.encode('unicode-escape').decode('utf-8')
>>>print('original: ' + u.encode("utf-8").decode('unicode-escape'))
original:   χαν  хан

ursprüngliche Ressource: https://blog.csdn.net/chuatony/article/details/72628868

ChrisXiao
quelle
-3

Die Verwendung von sure_ascii = False in json.dumps ist die richtige Richtung, um dieses Problem zu lösen, wie Martijn hervorhob. Dies kann jedoch eine Ausnahme auslösen:

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

Sie benötigen zusätzliche Einstellungen in site.py oder sitecustomize.py, um sys.getdefaultencoding () korrekt einzustellen. site.py befindet sich unter lib / python2.7 / und sitecustomize.py befindet sich unter lib / python2.7 / site-packages.

Wenn Sie site.py verwenden möchten, ändern Sie unter def setencoding (): das erste if 0: in if 1:, damit Python das Gebietsschema Ihres Betriebssystems verwendet.

Wenn Sie sitecustomize.py bevorzugen, die möglicherweise nicht vorhanden ist, wenn Sie sie nicht erstellt haben. Setzen Sie einfach diese Zeilen:

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

Dann können Sie eine chinesische json-Ausgabe im utf-8-Format ausführen, z.

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

Sie erhalten eine utf-8-codierte Zeichenfolge anstelle einer maskierten JSON-Zeichenfolge.

So überprüfen Sie Ihre Standardcodierung:

print sys.getdefaultencoding()

Sie sollten "utf-8" oder "UTF-8" erhalten, um Ihre Einstellungen für site.py oder sitecustomize.py zu überprüfen.

Bitte beachten Sie, dass Sie sys.setdefaultencoding ("utf-8") in der interaktiven Python-Konsole nicht ausführen konnten.

Ryan X.
quelle
2
Nein. Tu es nicht. Das Ändern der Standardzeichenkodierung hat nichts mit json's zu tun ensure_ascii=False. Geben Sie ein minimales vollständiges Codebeispiel an, wenn Sie anders denken.
JFS
Sie erhalten diese Ausnahme nur, wenn Sie entweder Nicht-ASCII- Byte-Zeichenfolgen (z. B. keine Unicode-Werte) eingeben oder versuchen, den resultierenden JSON-Wert (eine Unicode-Zeichenfolge) mit einer Nicht-ASCII-Byte-Zeichenfolge zu kombinieren. Das Festlegen der Standardcodierung auf UTF-8 maskiert im Wesentlichen ein zugrunde liegendes Problem, wenn Sie Ihre Zeichenfolgendaten nicht ordnungsgemäß verwalten.
Martijn Pieters