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 ?


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

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

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

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"}

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": "ƒ"}

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

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]

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

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


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.


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


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


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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.