Utf-8 metinlerini json.dumps içinde \ u escape sırası olarak değil, UTF8 olarak kaydetme


474

basit kod:

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

Sorun: insan tarafından okunamıyor. (Akıllı) kullanıcılarım, JSON dökümleriyle metin dosyalarını doğrulamak veya hatta düzenlemek istiyor (ve XML kullanmak istemiyorum).

Nesneleri (yerine \uXXXX) UTF-8 JSON dizelerine serileştirmenin bir yolu var mı ?


9
for :)))
rubmz

Yanıtlar:


642

Kullanım ensure_ascii=Falseiçin anahtarı json.dumps(), daha sonra UTF-8 el değerini kodlamak:

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

Bir dosyaya yazıyorsanız, json.dump()kodlamak için onu kullanın ve dosya nesnesine bırakın:

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

Python 2 için uyarılar

Python 2 için dikkate alınması gereken bazı uyarılar var. Eğer bir dosyaya bu yazıyorsanız, kullanabilirsiniz io.open()yerine open()daha sonra, yazma kullandıkça sizin için Unicode değerleri kodlar dosya nesnesini üretmek için json.dump()o dosyaya yazma yerine:

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

Bir olduğu not Do bulunan böcek jsonmodülüensure_ascii=False bayrak bir üretebilir karışımı içinde unicodeve strnesneleri. Python 2 için geçici çözüm şöyledir:

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

Python 2'de, strUTF-8 olarak kodlanmış bayt dizeleri (tip ) kullanırken, encodinganahtar kelimeyi de ayarladığınızdan emin olun :

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

Bir dosyaya yazmak için

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)

Stdout'a yazdırmak için

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

1
Sözdizimi Hatası: 5. satırda json-utf8.py dosyasında ASCII olmayan '\ xc3' karakteri, ancak kodlama bildirilmedi; ayrıntılar için bkz. python.org/dev/peps/pep-0263
Alex

Teşekkür ederim! Bu kadar basit olduğunu fark etmedim. Yalnızca json'a dönüştürdüğünüz verilerin güvenilmeyen kullanıcı girişi olması durumunda dikkatli olmanız gerekir.
Karim Sonbol

@Alex bu sorunun nasıl önleneceğini anladınız mı?
Gabriel Fuarı

@ Gabriel açıkçası hatırlamıyorum.
Alex

Sadece codecskütüphaneyi kullanarak benim için çalıştı . Teşekkürler!
igorkf

29

GÜNCELLEME: Bu yanlış cevap, ancak neden yanlış olduğunu anlamak hala yararlı. Yorumlara bakınız.

Nasıl unicode-escape?

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

9
unicode-escapegerekli değildir: json.dumps(d, ensure_ascii=False).encode('utf8')bunun yerine kullanabilirsiniz . Ve json'un her durumda Python'daki codec ile tam olarak aynı kuralları kullandığı garanti edilmez , yani, bazı köşe durumlarında sonuç aynı olabilir veya olmayabilir. Downvote, gereksiz ve muhtemelen yanlış bir dönüşüm içindir. İlgisiz: yalnızca utf8 yerel ayarları için veya envvar burada utf8 belirtiyorsa çalışır (bunun yerine Unicode yazdır). unicode-escapeprint json_strPYTHONIOENCODING
jfs

3
Başka bir sorun: dize değerlerindeki çift tırnaklar kaçışlarını kaybeder, bu da JSON çıktısının kırılmasına neden olur .
Martijn Pieters

Python3: AttributeError: 'str' nesnesinin 'decode' özelliği yok
Gank

1
unicode-escape iyi çalışıyor! Bu cevabı doğru olarak kabul ediyorum.
İşçi

@jfs Hayır, json.dumps(d, ensure_ascii=False).encode('utf8')en azından benim için çalışmıyor. UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position ...-Bir hata alıyorum . Ancak unicode-escapevaryant iyi çalışıyor.
turingtested

24

Peters'in python 2 geçici çözümü kenar durumunda başarısız oluyor:

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)

Satır 3'ün .decode ('utf8') kısmında çöküyordu. Bu adımı ve ascii'nin özel muhafazasını önleyerek programı çok daha basit hale getirerek sorunu çözdüm:

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
'Edge case' benim açımdan aptalca denenmemiş bir hataydı. Kişisel unicode(data)yaklaşım daha iyi bir seçenek yerine istisna durumları kullanıyor. Not encoding='utf8'kelime argüman çıkışı ile ilgisi yoktur json.dumps()üretir; fonksiyonun aldığı strgirişi deşifre etmek için kullanılır .
Martijn Pieters

2
@MartijnPieters: ya daha basit: open('filename', 'wb').write(json.dumps(d, ensure_ascii=False).encode('utf8'))O da çalışır dumpsdöner (ascii okunur) str veya unicode nesne.
jfs

@JFSebastian: doğru, çünkü str.encode('utf8') deşifre örtük ilk. Ama unicode(data)eğer bir strnesne verilirse de öyle . :-) io.open()BOM yazan bir codec bileşeni kullanmak da dahil olmak üzere size daha fazla seçenek sunar ve JSON verilerini başka bir şeyle takip ediyorsunuz.
Martijn Pieters

@MartijnPieters: -based .encode('utf8')varyantı hem Python 2 hem de 3 (aynı kod) üzerinde çalışır. unicodePython 3'te hiç yoktur . İlgisiz: json dosyaları BOM kullanmamalıdır (doğrulayan bir json ayrıştırıcısı BOM'yi göz ardı edebilir, bkz. Errate 3983 ).
jfs

ekleyerek encoding='utf8'için json.dumpssorun çözer. PS Ben dökümü Kiril bir metin var
Max L

8

Python 3.7'den itibaren aşağıdaki kod düzgün çalışır:

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

Çıktı:

{"symbol": "ƒ"}

2
ayrıca python 3.6'da (sadece doğrulandı).
Berry Tsakala

7

Aşağıdaki benim anlayış var okuma cevap yukarıdaki ve 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

İşte json.dump () kullanarak benim çözüm:

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)

burada SYSTEM_ENCODING şu şekilde ayarlanır:

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

4

Mümkünse codec bileşenleri kullanın,

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

1

Buradaki orijinal cevap için teşekkürler. İle piton 3 Aşağıdaki kod satırı:

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

iyiydi. Zorunlu değilse kodda çok fazla metin yazmamaya çalışın.

Bu, python konsolu için yeterince iyi olabilir. Ancak, bir sunucuyu tatmin etmek için yerel ayarı burada açıklandığı gibi ayarlamanız gerekebilir (apache2 üzerindeyse) http://blog.dscpl.com.au/2014/09/setting-lang-and-lcall-when-using .html

temelde ubuntu üzerinde he_IL veya herhangi bir dil yerel ayarının yüklü olmadığını kontrol edin

locale -a 

XX sizin diliniz olduğu yere kurun

sudo apt-get install language-pack-XX

Örneğin:

sudo apt-get install language-pack-he

/ etc / apache2 / envvrs dosyasına aşağıdaki metni ekleyin

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

Umarım apache'den python hataları almazsınız:

print (js) UnicodeEncodeError: 'ascii' codec bileşeni 41-45 arasındaki karakterleri kodlayamıyor: sıra değeri aralıkta değil (128)

Ayrıca apache'de utf burada açıklandığı gibi varsayılan kodlamayı yapmaya çalışın: Apache
için varsayılan kodlamayı UTF-8 olarak nasıl değiştirebilirim?

Apache hataları hata ayıklamak için acı olabilir ve yanlışlıkla bu durumda python'dan olduğunu düşünebilirsiniz çünkü erken yapın


1

Bir dosya ve dosya içeriğinden JSON dizesi yüklüyorsanız arapça metinler. O zaman bu işe yarayacak.

Varsayım Dosya gibi: arabic.json

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

Arabic.json dosyasından arapça içeriğini al

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)

Django Şablonunda JSON Verilerini kullanmak için aşağıdaki adımları izleyin:

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

json.JSONDecoder().decode(json_data2)

bitmiş! Şimdi sonuçları Arapça değere sahip JSON endeksi olarak alabiliriz.


fh.close() fhtanımsız.
AMC

BT şimdi düzeltildi. Bu olurduf.close()
Chandan Sharma

0

problemi çözmek için unicode-escape kullan

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

açıklamak

>>>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:   χαν  хан

orijinal kaynak :https://blog.csdn.net/chuatony/article/details/72628868


-3

Martijn tarafından işaret edildiği gibi json.dumps içinde sure_ascii = False kullanılması bu sorunu çözmek için doğru yoldur. Ancak, bu bir istisna oluşturabilir:

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

Sys.getdefaultencoding () yönteminizi doğru ayarlamak için site.py veya sitecustomize.py dosyalarında ek ayarlara ihtiyacınız vardır. site.py lib / python2.7 / altında ve sitecustomize.py lib / python2.7 / site paketleri altındadır.

Site.py kullanmak istiyorsanız, def setencoding (): altında, eğer 0: değerini 1: ise 1: olarak değiştirin, böylece python işletim sisteminizin yerel ayarını kullanır.

Sitecustomize.py kullanmayı tercih ederseniz, oluşturmadıysanız mevcut olmayabilir. sadece bu satırları koyun:

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

Sonra utf-8 formatında bazı Çince json çıktıları yapabilirsiniz, örneğin:

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

\ U Kaçan json dizesi yerine utf-8 kodlu bir dize alırsınız.

Varsayılan kodlamanızı doğrulamak için:

print sys.getdefaultencoding()

Site.py veya sitecustomize.py ayarlarınızı doğrulamak için "utf-8" veya "UTF-8" almanız gerekir.

Etkileşimli python konsolunda sys.setdefaultencoding ("utf-8") yapamayacağınızı lütfen unutmayın.


2
Hayır. Yapma. Varsayılan karakter kodlamasının değiştirilmesinin json's ile ilgisi yoktur ensure_ascii=False. Aksini düşünüyorsanız, tam bir kod örneği sağlayın.
jfs

Bu istisnayı, yalnızca ASCII olmayan bayt dizeleri (örn. Unicode değerleri değil) ile beslerseniz veya elde edilen JSON değerini (bir Unicode dizesi) ASCII olmayan bir bayt dizesiyle birleştirmeye çalışırsanız alırsınız . Varsayılan kodlamanın UTF-8 olarak ayarlanması, temel olarak dize verilerinizi düzgün yönetmediğinizde temeldeki bir sorunu maskeliyordur.
Martijn Pieters
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.