UnicodeEncodeError: 'charmap' codec can't encode - character maps to , print function [duplicate]
UnicodeEncodeError: кодек 'charmap' не может кодировать сопоставления символов в , функция печати
Я пишу программу на Python (Python 3.3) для отправки некоторых данных на веб-страницу с использованием метода POST . В основном для процесса отладки я получаю результат страницы и отображаю его на экране с помощью функции print().
HTTPResponse.read() метод возвращает bytes элемент, кодирующий страницу (которая является хорошо отформатированным документом UTF-8) Все казалось нормальным, пока я не перестал использовать IDLE GUI для Windows и вместо этого использовал консоль Windows. Возвращаемая страница содержит символ U + 2014 (em-тире), который функция печати хорошо переводит в графическом интерфейсе Windows (я полагаю, кодовая страница 1252), но не в консоли Windows (кодовая страница 850). Учитывая strict поведение по умолчанию, я получаю следующую ошибку:
UnicodeEncodeError: 'charmap' codec can't encode character '\u2014' in position 10248: character maps to <undefined>
Я мог бы исправить это, используя этот довольно уродливый код:
Теперь он заменяет недопустимый символ "—" на ? . Не идеальный вариант (дефис должен быть лучшей заменой), но достаточно хорош для моих целей.
Есть несколько вещей, которые мне не нравятся в моем решении.
Код уродлив со всем этим декодированием, кодировкой и еще раз декодированием.
Это решает проблему только для этого случая. Если я перенесу программу для системы, использующей какую-либо другую кодировку (latin-1, cp437, обратно в cp1252 и т.д.), Она должна распознать целевую кодировку. Это не так. (например, при повторном использовании графического интерфейса IDLE также теряется emdash, чего раньше не было)
Было бы лучше, если бы emdash переводился в дефис вместо запроса bang.
Проблема не в emdash (я могу придумать несколько способов решить именно эту проблему), но мне нужно написать надежный код. Я загружаю на страницу данные из базы данных, и эти данные могут возвращаться. Я могу предвидеть множество других конфликтующих случаев: 'Á' U + 00c1 (что возможно в моей базе данных) может переводиться в CP-850 (кодировка консоли DOS / Windows для западноевропейских языков), но не в CP-437 (кодировка американского английского, которая используется по умолчанию во многих установках Windows).
Итак, вопрос:
Есть ли более приятное решение, которое делает мой код независимым от кодировки выходного интерфейса?
В этом примере любой непечатаемый символ в моем имени правильно заменяется вопросительным знаком.
Если вы создадите пользовательскую функцию печати , например, called myprint , используя эти механизмы для правильного кодирования выходных данных, вы можете просто заменить print на myprint везде, где это необходимо, не делая весь код уродливым.
Сбросьте кодировку вывода глобально в начале работы программного обеспечения:
На странице http://www.macfreek.nl/memory/Encoding_of_Python_stdout есть хорошее краткое описание того, что нужно сделать, чтобы изменить кодировку вывода. Особенно интересен раздел "StreamWriter-оболочка вокруг стандартного вывода". По сути, в нем говорится об изменении функции кодирования ввода-вывода следующим образом:
В Python 2:
if sys.stdout.encoding != 'cp850': sys.stdout = codecs.getwriter('cp850')(sys.stdout, 'strict') if sys.stderr.encoding != 'cp850': sys.stderr = codecs.getwriter('cp850')(sys.stderr, 'strict')
В Python 3:
if sys.stdout.encoding != 'cp850': sys.stdout = codecs.getwriter('cp850')(sys.stdout.buffer, 'strict') if sys.stderr.encoding != 'cp850': sys.stderr = codecs.getwriter('cp850')(sys.stderr.buffer, 'strict')
Если используется при выводе HTML CGI, вы можете заменить 'strict' на 'xmlcharrefreplace', чтобы получить теги в HTML-кодировке для непечатаемых символов.
Не стесняйтесь изменять подходы, устанавливая разные кодировки.... Обратите внимание, что по-прежнему не работает вывод неопределенных данных. Таким образом, любые данные, входные данные, тексты должны быть корректно преобразованы в unicode:
# -*- coding: utf-8 -*- import sys import codecs sys.stdout = codecs.getwriter("iso-8859-1")(sys.stdout, 'xmlcharrefreplace') printu"Stöcker"# works print"Stöcker".decode("utf-8") # works print"Stöcker"# fails
Ответ 2
Основываясь на ответе Дирка Стекера , вот аккуратная функция-оболочка для функции print в Python 3. Используйте ее так же, как вы использовали бы print .
В качестве дополнительного бонуса, по сравнению с другими ответами, ваш текст будет напечатан не как bytearray ('b"content"') , а как обычные строки ('content'), из-за последнего шага декодирования.
Для целей отладки вы могли бы использовать print(repr(data)).
Для отображения текста всегда выводите Юникод. Не вводите жестко кодировку символов вашей среды, такую как Cp850, внутри вашего скрипта. Чтобы расшифровать HTTP-ответ, см. Хороший способ получить кодировку HTTP-ответа в Python.