Проблема декодирования Python с китайскими иероглифами

Я использую Python 3.5 и пытаюсь взять блок байтового текста, который может содержать или не содержать специальные китайские символы, и вывести его в файл. Он работает для записей, которые не содержат китайских иероглифов, но ломается, когда они есть. Китайские иероглифы всегда являются именем человека и всегда добавляются к английскому написанию его имени. Текст отформатирован в формате JSON и должен быть декодирован, прежде чем я смогу его загрузить. Декодирование, кажется, идет нормально и не дает мне никаких ошибок. Когда я пытаюсь записать декодированный текст в файл, появляется следующее сообщение об ошибке:

UnicodeEncodeError: кодек 'charmap' не может кодировать символы в позициях 14-18: сопоставление символов с неопределенными значениями

Вот пример необработанных данных, которые я получаю до того, как что-либо с ними делаю:

 b'  "isBulkRecipient": "false",\r\n      "name": "Name in, English \xef'
 b'\xab\x62\xb6\xe2\x15\x8a\x8b\x8a\xee\xab\x89\xcf\xbc\x8a",\r\n

Вот код, который я использую:

recipientData = json.loads(recipientContent.decode('utf-8', 'ignore'))
recipientName = recipientData['signers'][0]['name']
pprint(recipientName)
with open('envelope recipient list.csv', 'a', newline='') as fp:
    a = csv.writer(fp, delimiter=',')
    csvData = [[recipientName]]
    a.writerows(csvData)

recipientContent получается из вызова API. Мне не нужны китайские иероглифы в выходном файле. Любой совет будет принят с благодарностью!

Обновлять:

Я делал некоторые обходные пути вручную для каждой ломающейся записи, и появились другие записи, которые не содержали китайских специальных символов, но содержали их из других языков, и это также сломало программу. Специальные символы есть только в поле имени. Таким образом, имя может быть чем-то вроде «Алекс», где оно представляет собой смесь обычных и специальных символов. Прежде чем я декодирую строку, содержащую эту информацию, я могу распечатать ее на экране, и она выглядит так: b'name": "A\xc5ex",\r\n

Но после того, как я декодирую его в utf-8, он выдаст мне ошибку, если я попытаюсь вывести его. Сообщение об ошибке: UnicodeEncodeError: 'charmap' codec can't encode character 'u0142' in position 2- character maps to -undefined-

Я посмотрел, что такое ł, и это специальный символ ł.


person Alex Hall    schedule 28.06.2016    source источник
comment
Строка примера не похожа на UTF-8 (и ни на одну из распространенных китайских многобайтовых кодировок). Вы уверены, что это кодировка UTF-8 (или даже китайский язык)?   -  person univerio    schedule 28.06.2016
comment
вы должны проверить Content-Type. Если это application/json; charset=utf-16, используйте utf-16. По умолчанию для application/json используется utf-8.   -  person Nizam Mohamed    schedule 28.06.2016
comment
Я не уверен на 100%, что это utf-8, потому что веб-сервис, из которого я получаю данные, не очень хорошо задокументирован, но я пробовал несколько разных типов кодирования, включая utf-16. Я уверен, что он содержит китайские иероглифы.   -  person Alex Hall    schedule 28.06.2016
comment
каждый http-ответ имеет Content-Type. Вы должны проверить это перед декодированием.   -  person Nizam Mohamed    schedule 28.06.2016
comment
Ваше право Низам спасибо. Я проверил, и это дало мне 'content-type': 'application/json; charset=utf-8'   -  person Alex Hall    schedule 28.06.2016
comment
Вы на винде? Можете ли вы опубликовать полную трассировку?   -  person univerio    schedule 29.06.2016


Ответы (3)


Ошибка, которую вы получаете, возникает при записи в файл.

В Python 3.x, когда вы open() в текстовом режиме (по умолчанию) без указания encoding=, Python будет использовать кодировку, наиболее подходящую для вашей локали или языковых настроек.

Если вы работаете в Windows, для сопоставления с кодировкой вашего языка будет использоваться кодек charmap.

Хотя вы можете просто записывать байты прямо в файл, вы поступаете правильно, сначала декодируя его. Как уже говорили другие, вы действительно должны декодировать, используя кодировку, указанную веб-сервером. Вы также можете использовать модуль Python Requests, который сделает это за вас. (Ваш пример не декодируется как UTF-8, поэтому я предполагаю, что ваш пример неверен)

Чтобы решить вашу немедленную ошибку, просто передайте encoding в open(), который поддерживает символы, которые есть в ваших данных. Юникод в кодировке UTF-8 — очевидный выбор. Поэтому вы должны изменить свой код, чтобы читать:

with open('envelope recipient list.csv', 'a', encoding='utf-8', newline='') as fp:
person Alastair McCormack    schedule 03.07.2016

Предупреждение: решение с дробовиком впереди

Предполагая, что вы просто хотите избавиться от всех посторонних символов во всем вашем файле (то есть они не важны для вашей будущей обработки всех других полей), вы можете просто игнорировать все символы, отличные от ascii.

recipientData = json.loads(recipientContent.decode('utf-8', 'ignore'))

by

recipientData = json.loads(recipientContent.decode('ascii', 'ignore'))

таким образом вы удаляете все символы, отличные от ascii, перед будущей обработкой.

Я назвал это решением дробовика, потому что при определенных обстоятельствах оно может работать некорректно:

  1. Очевидно, если символы, отличные от ascii, необходимы для использования в будущем
  2. Если символы b'\' или b" появляются, например, из части символа utf-16.
person Xavier Combelle    schedule 30.06.2016

Добавьте эту строку в свой код:

from __future__ import unicode_literals
person khelili miliana    schedule 03.07.2016
comment
Почему это поможет? - person Alastair McCormack; 03.07.2016