Сохранение текстов utf-8 в json.dumps как UTF8, а не как escape-последовательность
Образец кода:
>>> import json
>>> json_string = json.dumps("ברי צקלה")
>>> print json_string
"\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4"
Проблема: она не читается человеком. Мои (умные) пользователи хотят проверять или даже редактировать текстовые файлы с помощью дампов JSON. (и я бы предпочел не использовать XML)
Есть ли способ сериализации объектов в строку JSON UTF-8 (вместо \uXXXX)?
это не поможет
>>> output = json_string.decode('string-escape')
"\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4"
это работает, но если какой-либо подобъект является Python-Unicode, а не UTF-8, он будет выводить мусор:
>>> #### 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']
××¨× ×¦×§××
8 ответов
Использовать ensure_ascii=False
переключиться на json.dumps()
, затем закодируйте значение в 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
"ברי צקלה"
Если вы пишете это в файл, вы можете использовать io.open()
вместоopen()
чтобы создать объект файла, который кодирует значения Unicode для вас, как вы пишете, а затем используйтеjson.dump()
вместо этого, чтобы написать в этот файл:
with io.open('filename', 'w', encoding='utf8') as json_file:
json.dump(u"ברי צקלה", json_file, ensure_ascii=False)
В Python 3 встроенныйopen()
это псевдоним дляio.open()
, Обратите внимание, что есть ошибка вjson
модуль, в котором ensure_ascii=False
флаг может производить смесь unicode
а также str
объекты. Обходной путь для Python 2:
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))
Если вы передаете байтовые строки (введите str
в Python 2, bytes
в Python 3), закодированный в UTF-8, убедитесь, что также установлен 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']
ברי צקלה
Обратите внимание, что ваш второй пример не является допустимым Unicode; Вы дали ему UTF-8 байтов как литерал Unicode, который никогда не будет работать:
>>> s = u'\xd7\x91\xd7\xa8\xd7\x99 \xd7\xa6\xd7\xa7\xd7\x9c\xd7\x94'
>>> print s
××¨× ×¦×§××
>>> print s.encode('latin1').decode('utf8')
ברי צקלה
Только когда я закодировал эту строку в латиницу 1 (чьи кодовые точки Unicode отображают один в один в байты), а затем декодировал как UTF-8, вы видите ожидаемый результат. Это не имеет ничего общего с JSON, и все, что связано с тем, что вы используете неправильный ввод. Результат называется моджибаке.
Если вы получили это значение Unicode из строкового литерала, оно было декодировано с использованием неправильного кодека. Возможно, ваш терминал неправильно настроен или ваш текстовый редактор сохранил ваш исходный код, используя другой кодек, чем тот, который вы указали Python для чтения файла. Или вы получили это из библиотеки, которая применила неправильный кодек. Все это не имеет ничего общего с библиотекой JSON.
Просто как торт
Написать в файл
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)
Для печати на стандартный ввод
import codecs
import json
print(json.dumps({"message":"xin chào việt nam"}, ensure_ascii=False))
Обходной путь Peters 2 для Python 2 завершается неудачно:
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)
Это было сбой в части.decode('utf8') строки 3. Я исправил проблему, сделав программу намного проще, избегая этого шага, а также особый корпус 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"}
ОБНОВЛЕНИЕ: Это неправильный ответ, но все же полезно понять, почему это неправильно. Смотрите комментарии.
Как насчет unicode-escape
?
>>> d = {1: "ברי צקלה", 2: u"ברי צקלה"}
>>> json_str = json.dumps(d).decode('unicode-escape').encode('utf8')
>>> print json_str
{"1": "ברי צקלה", "2": "ברי צקלה"}
Начиная с Python 3.7, следующий код работает нормально:
from json import dumps
result = {"symbol": "ƒ"}
json_string = dumps(result, sort_keys=True, indent=2, ensure_ascii=False)
print(json_string)
Выход:
{"symbol": "ƒ"}
Спасибо за оригинальный ответ здесь. С python 3 следующая строка кода:
print(json.dumps(result_dict,ensure_ascii=False))
было нормально. Попробуйте не писать слишком много текста в коде, если это не обязательно.
Этого может быть достаточно для консоли python. Однако для удовлетворения требований сервера вам может потребоваться установить языковой стандарт, как описано здесь (если он находится на apache2) http://blog.dscpl.com.au/2014/09/setting-lang-and-lcall-when-using.html
в основном установите he_IL или любой другой языковой стандарт на ubuntu, проверьте, что он не установлен
locale -a
установите его, где XX - ваш язык
sudo apt-get install language-pack-XX
Например:
sudo apt-get install language-pack-he
добавьте следующий текст в /etc/apache2/envvrs
export LANG='he_IL.UTF-8'
export LC_ALL='he_IL.UTF-8'
Чем вы, надеюсь, не получите ошибок python из apache, например:
print (js) UnicodeEncodeError: кодек ascii не может кодировать символы в позиции 41-45: порядковый номер не в диапазоне (128)
Также в apache попробуйте сделать utf кодировкой по умолчанию, как описано здесь:
Как изменить кодировку по умолчанию на UTF-8 для Apache?
Сделайте это заранее, потому что ошибки apache могут быть болезненными для отладки, и вы можете ошибочно подумать, что это из python, что, возможно, не так в этой ситуации.
используйте unicode-escape для решения проблемы
>>>import json
>>>json_string = json.dumps("ברי צקלה")
>>>json_string.encode('ascii').decode('unicode-escape')
'"ברי צקלה"'
объяснять
>>>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: 漢 χαν хан
Исходный ресурс :https://blog.csdn.net/chuatony/article/details/72628868
Следующее мое понимание var читая ответ выше и гугл.
# 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://stackru.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://stackru.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'
"""
Если вы загружаете строку JSON из файла, и файл содержит арабские тексты. Тогда это сработает.
Предположим, файл вроде: arabic.json
{
"key1" : "لمستخدمين",
"key2" : "إضافة مستخدم"
}
Получите арабское содержимое из файла 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)
Чтобы использовать данные JSON в шаблоне Django, выполните следующие действия:
# If have to get the JSON index in Django Template file, then simply decode the encoded string.
json.JSONDecoder().decode(json_data2)
сделанный! Теперь мы можем получить результаты в виде индекса JSON с арабским значением.
Вот мое решение с использованием 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)
где SYSTEM_ENCODING установлен в:
locale.setlocale(locale.LC_ALL, '')
SYSTEM_ENCODING = locale.getlocale()[1]
Используйте кодеки, если это возможно,
with codecs.open('file_path', 'a+', 'utf-8') as fp:
fp.write(json.dumps(res, ensure_ascii=False))
Использование sure_ascii=False в json.dumps - правильное направление для решения этой проблемы, как отметил Мартейн. Однако это может вызвать исключение:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 1: ordinal not in range(128)
Вам нужны дополнительные настройки в site.py или sitecustomize.py, чтобы правильно настроить sys.getdefaultencoding(). site.py находится в lib/python2.7/, а sitecustomize.py находится в lib/python2.7/site-packages.
Если вы хотите использовать site.py, в def setencoding(): измените первое, если 0: на, если 1: так, чтобы python использовал локаль вашей операционной системы.
Если вы предпочитаете использовать sitecustomize.py, который может не существовать, если вы его еще не создали. просто поместите эти строки:
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
Затем вы можете сделать некоторые китайские выходные данные в формате json в формате utf-8, например:
name = {"last_name": u"王"}
json.dumps(name, ensure_ascii=False)
Вы получите строку в кодировке utf-8 вместо \u экранированной строки json.
Чтобы проверить кодировку по умолчанию:
print sys.getdefaultencoding()
Вы должны получить "utf-8" или "UTF-8", чтобы проверить ваши настройки site.py или sitecustomize.py.
Обратите внимание, что вы не можете выполнить sys.setdefaultencoding("utf-8") на интерактивной консоли Python.