Lưu văn bản utf-8 trong json.dumps dưới dạng UTF8, không phải là chuỗi thoát \ u


474

mã mẫu:

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

Vấn đề: nó không thể đọc được. Người dùng (thông minh) của tôi muốn xác minh hoặc thậm chí chỉnh sửa các tệp văn bản bằng các kết xuất JSON (và tôi không muốn sử dụng XML).

Có cách nào để tuần tự hóa các đối tượng thành các chuỗi JSON UTF-8 (thay vì \uXXXX) không?


9
+ cho ב ž י :)))
rubmz

Câu trả lời:


642

Sử dụng ensure_ascii=Falsechuyển đổi sang json.dumps(), sau đó mã hóa giá trị thành UTF-8 theo cách thủ công:

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

Nếu bạn đang ghi vào một tệp, chỉ cần sử dụng json.dump()và để nó vào đối tượng tệp để mã hóa:

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

Hãy cẩn thận cho Python 2

Đối với Python 2, có một số lưu ý khác cần tính đến. Nếu bạn đang ghi điều này vào một tệp, bạn có thể sử dụng io.open()thay vì open()tạo một đối tượng tệp mã hóa các giá trị Unicode cho bạn khi bạn viết, sau đó sử dụng json.dump()để ghi vào tệp đó:

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

Do lưu ý rằng có một lỗi trong các jsonmô-đun nơi ensure_ascii=Falsecờ có thể tạo ra một sự pha trộn của unicodestrđối tượng. Cách giải quyết cho Python 2 là:

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

Trong Python 2, khi sử dụng chuỗi byte (loại str), được mã hóa thành UTF-8, hãy đảm bảo cũng đặt encodingtừ khóa:

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

Để ghi vào một tập tin

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)

Để in ra thiết bị xuất chuẩn

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

1
Cú pháp: Ký tự không phải ASCII '\ xc3' trong tệp json-utf8.py trên dòng 5, nhưng không khai báo mã hóa; xem python.org/dev/peps/pep-0263 để biết chi tiết
Alex

Cảm ơn bạn! Tôi đã không nhận ra nó đơn giản. Bạn chỉ cần cẩn thận nếu dữ liệu bạn đang chuyển đổi sang json là đầu vào của người dùng không đáng tin cậy.
Karim Sonbol

@Alex bạn đã tìm ra cách để tránh vấn đề đó chưa?
Hội chợ Gabriel

@Gabriel thẳng thắn, tôi không nhớ. Không có gì quá quan trọng để đặt đoạn trích sang một bên :(
Alex

Chỉ làm việc cho tôi bằng cách sử dụng codecsthư viện. Cảm ơn!
igorkf

29

CẬP NHẬT: Đây là câu trả lời sai, nhưng vẫn hữu ích để hiểu tại sao nó sai. Xem ý kiến.

Thế còn unicode-escape?

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

9
unicode-escapelà không cần thiết: bạn có thể sử dụng json.dumps(d, ensure_ascii=False).encode('utf8')thay thế. Và không đảm bảo rằng json sử dụng chính xác các quy tắc giống như unicode-escapecodec trong Python trong mọi trường hợp, nghĩa là, kết quả có thể hoặc không giống nhau trong một số trường hợp góc. Các downvote là cho một chuyển đổi không cần thiết và có thể sai. Không liên quan: print json_strchỉ hoạt động cho các ngôn ngữ utf8 hoặc nếu PYTHONIOENCODINGenvvar chỉ định utf8 tại đây (in Unicode thay thế).
JFS

3
Một vấn đề khác: bất kỳ dấu ngoặc kép nào trong các giá trị chuỗi sẽ mất khả năng thoát, do đó, điều này sẽ dẫn đến đầu ra JSON bị hỏng .
Martijn Pieters

lỗi trong Python3: AttributionError: đối tượng 'str' không có thuộc tính 'giải mã'
Gank

1
unicode-thoát hoạt động tốt! Tôi sẽ chấp nhận câu trả lời này là chính xác.
Công nhân

@jfs Không, json.dumps(d, ensure_ascii=False).encode('utf8')ít nhất là không hoạt động. Tôi đang nhận được UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position ...-error. Các unicode-escapebiến thể hoạt động tốt tuy nhiên.
turingtested

24

Cách giải quyết python 2 của Peters không thành công trên một trường hợp cạnh:

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)

Nó đã bị sập trên phần .decode ('utf8') của dòng 3. Tôi đã khắc phục sự cố bằng cách làm cho chương trình đơn giản hơn nhiều bằng cách tránh bước đó cũng như vỏ bọc đặc biệt của 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"}

2
'Trường hợp cạnh' chỉ đơn giản là một lỗi chưa được kiểm tra về phía tôi. unicode(data)Cách tiếp cận của bạn là lựa chọn tốt hơn thay vì sử dụng xử lý ngoại lệ. Lưu ý rằng encoding='utf8'đối số từ khóa không liên quan gì đến đầu ra json.dumps()tạo ra; nó được sử dụng để giải mã strđầu vào mà hàm nhận được.
Martijn Pieters

2
@MartijnPieters: hoặc đơn giản hơn: open('filename', 'wb').write(json.dumps(d, ensure_ascii=False).encode('utf8'))Nó hoạt động cho dù dumpstrả về (chỉ ascii) đối tượng str hoặc unicode.
jfs

@JFSebastian: đúng, vì str.encode('utf8') giải mã ngầm trước. Nhưng như vậy unicode(data), nếu được đưa ra một strđối tượng. :-) Việc sử dụng io.open()cung cấp cho bạn nhiều tùy chọn hơn, bao gồm cả việc sử dụng codec ghi BOM và bạn đang theo dõi dữ liệu JSON bằng một thứ khác.
Martijn Pieters

@MartijnPieters: .encode('utf8')Biến thể dựa trên hoạt động trên cả Python 2 và 3 (cùng mã). Không có unicodetrên Python 3. Không liên quan: các tệp json không nên sử dụng BOM (mặc dù trình phân tích cú pháp json xác nhận có thể bỏ qua BOM, xem lỗi 3983 ).
JFS

thêm vào encoding='utf8'để json.dumpsgiải quyết vấn đề. Tái bút: Tôi có một văn bản cyrillic để kết xuất
Max L

8

Kể từ Python 3.7, đoạn mã sau hoạt động tốt:

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

Đầu ra:

{"symbol": "ƒ"}

2
cũng trong python 3.6 (chỉ cần xác minh).
Berry Tsakala

7

Sau đây là hiểu biết của tôi var đọc câu trả lời ở trên và 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

Đây là giải pháp của tôi bằng cách sử dụng 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)

trong đó HỆ THỐNG_PHẦN được đặt thành:

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

4

Sử dụng codec nếu có thể,

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

1

Cảm ơn câu trả lời ban đầu ở đây. Với python 3 dòng mã sau:

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

đã ổn Cân nhắc cố gắng không viết quá nhiều văn bản trong mã nếu nó không bắt buộc.

Điều này có thể đủ tốt cho giao diện điều khiển python. Tuy nhiên, để đáp ứng máy chủ, bạn có thể cần đặt ngôn ngữ như được giải thích ở đây (nếu là trên apache2) http://blog.dscpl.com.au/2014/09/setting-lang-and-lcall-when-USE .html

về cơ bản cài đặt he_IL hoặc bất kỳ ngôn ngữ địa phương nào trên ubfox, hãy kiểm tra xem nó chưa được cài đặt chưa

locale -a 

cài đặt nó trong đó XX là ngôn ngữ của bạn

sudo apt-get install language-pack-XX

Ví dụ:

sudo apt-get install language-pack-he

thêm văn bản sau vào / etc / apache2 / envvrs

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

Hơn bạn hy vọng sẽ không nhận được lỗi python từ apache như:

print (js) UnicodeEncodeError: 'ascii' codec không thể mã hóa các ký tự ở vị trí 41-45: thứ tự không nằm trong phạm vi (128)

Ngoài ra, trong apache, hãy thử sử dụng mã hóa mặc định như được giải thích ở đây:
Làm cách nào để thay đổi mã hóa mặc định thành UTF-8 cho Apache?

Làm điều đó sớm vì lỗi apache có thể gây khó khăn khi gỡ lỗi và bạn có thể nhầm tưởng đó là từ con trăn có thể không phải là trường hợp trong tình huống đó


1

Nếu bạn đang tải chuỗi JSON từ một tệp & nội dung tệp văn bản tiếng Ả Rập. Sau đó, điều này sẽ làm việc.

Giả sử tập tin như: arabic.json

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

Lấy nội dung tiếng Ả Rập từ tệp arabic.json

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)

Để sử dụng Dữ liệu JSON trong Mẫu Django, hãy làm theo các bước dưới đây:

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

json.JSONDecoder().decode(json_data2)

làm xong! Bây giờ chúng ta có thể nhận kết quả dưới dạng chỉ mục JSON với giá trị arabic.


fh.close() fhkhông định nghĩa được.
AMC

CNTT đã được sửa chữa ngay bây giờ. Nó sẽ làf.close()
Chandan Sharma

0

sử dụng unicode-esc để giải quyết vấn đề

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

giải thích

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

tài nguyên ban đầu https://blog.csdn.net/chuatony/article/details/72628868


-3

Sử dụng notify_ascii = false trong json.dumps là hướng đi đúng để giải quyết vấn đề này, như Martijn đã chỉ ra. Tuy nhiên, điều này có thể đưa ra một ngoại lệ:

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

Bạn cần các cài đặt bổ sung trong cả hai trang web hoặc sitecustomize.py để đặt sys.getdefaultencoding () của bạn chính xác. site.py nằm dưới lib / python2.7 / và sitecustomize.py nằm dưới lib / python2.7 / gói trang web.

Nếu bạn muốn sử dụng site.py, trong def setencoding (): thay đổi đầu tiên nếu 0: thành nếu 1: để python sẽ sử dụng ngôn ngữ của hệ điều hành của bạn.

Nếu bạn thích sử dụng sitecustomize.py, có thể không tồn tại nếu bạn chưa tạo. chỉ cần đặt những dòng này:

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

Sau đó, bạn có thể thực hiện một số đầu ra json Trung Quốc ở định dạng utf-8, chẳng hạn như:

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

Bạn sẽ nhận được một chuỗi mã hóa utf-8, thay vì chuỗi json đã thoát.

Để xác minh mã hóa mặc định của bạn:

print sys.getdefaultencoding()

Bạn nên lấy "utf-8" hoặc "UTF-8" để xác minh cài đặt trang web của bạn hoặc sitecustomize.py.

Xin lưu ý rằng bạn không thể thực hiện sys.setdefaultencoding ("utf-8") tại bảng điều khiển python tương tác.


2
Không. Đừng làm điều đó. Sửa đổi mã hóa ký tự mặc định không có gì để làm với json's ensure_ascii=False. Cung cấp một ví dụ mã hoàn chỉnh tối thiểu nếu bạn nghĩ khác.
JFS

Bạn chỉ nhận được ngoại lệ này nếu bạn cung cấp chuỗi byte không phải ASCII (ví dụ: không phải giá trị Unicode) hoặc cố gắng kết hợp giá trị JSON kết quả (chuỗi Unicode) với chuỗi byte không phải ASCII. Đặt mã hóa mặc định thành UTF-8 về cơ bản che giấu một vấn đề tiềm ẩn là bạn không quản lý dữ liệu chuỗi của mình đúng cách.
Martijn Pieters
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.