Ответ 1
Можете ли вы попробовать следующее?
with io.open("testJson.json",'w',encoding="utf-8") as outfile:
outfile.write(unicode(json.dumps(cards, ensure_ascii=False)))
У меня есть json файл, который, случается, содержит множество китайских и японских (и других языков) символов. Я загружаю его в свой python 2.7 script с помощью io.open
следующим образом:
with io.open('multiIdName.json', encoding="utf-8") as json_data:
cards = json.load(json_data)
Я добавляю новое свойство json, все хорошо. Затем я пытаюсь записать его обратно в другой файл:
with io.open("testJson.json",'w',encoding="utf-8") as outfile:
json.dump(cards, outfile, ensure_ascii=False)
Что, когда я получаю ошибку TypeError: must be unicode, not str
Я пробовал записывать outfile как двоичный файл (with io.open("testJson.json",'wb') as outfile:
), но в итоге получилось:
{"multiverseid": 262906, "name": "\u00e6\u00b8\u00b8\u00e9\u009a\u00bc\u00e7\u008b\u00ae\u00e9\u00b9\u00ab", "language": "Chinese Simplified"}
Я думал, что открытие и запись его в одной кодировке будет достаточно, а также флаг secure_ascii, но явно нет. Я просто хочу сохранить символы, которые существовали в файле, прежде чем я запустил script, не превращая их в\u's.
Можете ли вы попробовать следующее?
with io.open("testJson.json",'w',encoding="utf-8") as outfile:
outfile.write(unicode(json.dumps(cards, ensure_ascii=False)))
Причиной этой ошибки является абсолютно глупое поведение json.dumps
в Python 2:
>>> json.dumps({'a': 'a'}, ensure_ascii=False)
'{"a": "a"}'
>>> json.dumps({'a': u'a'}, ensure_ascii=False)
u'{"a": "a"}'
>>> json.dumps({'a': 'ä'}, ensure_ascii=False)
'{"a": "\xc3\xa4"}'
>>> json.dumps({u'a': 'ä'}, ensure_ascii=False)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/json/__init__.py", line 250, in dumps
sort_keys=sort_keys, **kw).encode(obj)
File "/usr/lib/python2.7/json/encoder.py", line 210, in encode
return ''.join(chunks)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: ordinal not in range(128)
Это связано с тем, что io.open
с encoding
устанавливает только принимает unicode
объекты (что само по себе является правильным) приводит к проблемам.
Тип возврата полностью зависит от того, какой тип ключей или значений в словаре, если ensure_ascii=False
, но str
всегда возвращается, если ensure_ascii=True
. Если вы случайно можете установить 8-битные строки в словари, вы не можете слепо преобразовать этот возвращаемый тип в unicode
, потому что вам нужно установить кодировку, предположительно UTF-8:
>>> x = json.dumps(obj, ensure_ascii=False)
>>> if isinstance(x, str):
... x = unicode(x, 'UTF-8')
В этом случае я считаю, что вы можете использовать json.dump
для записи в открытый двоичный файл; однако, если вам нужно сделать что-то более сложное с результирующим объектом, вам, вероятно, понадобится приведенный выше код.
Одним из решений является прекратить все это безумие кодирования/декодирования, переключившись на Python 3.
Модуль JSON обрабатывает для вас кодировку и декодирование, поэтому вы можете просто открывать входные и выходные файлы в двоичном режиме. Модуль JSON предполагает кодировку UTF-8, но может быть изменен с помощью атрибута encoding
в методах load()
и dump()
.
with open('multiIdName.json', 'rb') as json_data:
cards = json.load(json_data)
то:
with open("testJson.json", 'wb') as outfile:
json.dump(cards, outfile, ensure_ascii=False)
Забастовкa > Благодаря @Antti Haapala, модуль Python 2.x JSON предоставляет либо Unicode, либо str в зависимости от содержимого объекта.
Вам нужно будет добавить проверочный чек, чтобы убедиться, что результатом является Unicode перед тем, как писать через io
:
with io.open("testJson.json", 'w', encoding="utf-8") as outfile:
my_json_str = json.dumps(my_obj, ensure_ascii=False)
if isinstance(my_json_str, str):
my_json_str = my_json_str.decode("utf-8")
outfile.write(my_json_str)