Python, Unicode и консоль Windows

Когда я пытаюсь напечатать строку Unicode в консоли Windows, я получаю UnicodeEncodeError: 'charmap' codec can't encode character .... ошибка. Я предполагаю, что это потому, что консоль Windows не принимает символы только для Unicode. Какой лучший способ обойти это? Можно ли как-нибудь заставить Python автоматически распечатать ? вместо неудачи в этой ситуации?

Редактировать: я использую Python 2.5.


Примечание: @ LasseV.Karlsen ответ с галочкой устарел (с 2008 года). Пожалуйста, используйте решения / ответы / предложения ниже с осторожностью!

Ответ @JFSebastian более актуален на сегодняшний день (6 января 2016 года).

15 ответов

Решение

Примечание. Этот ответ устарел (с 2008 года). Пожалуйста, используйте решение ниже с осторожностью!


Вот страница, которая детализирует проблему и решение (найдите на странице текст Wrapping sys.stdout в экземпляр):

PrintFails - Python Wiki

Вот фрагмент кода с этой страницы:

$ python -c 'import sys, codecs, locale; print sys.stdout.encoding; \
    sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout); \
    line = u"\u0411\n"; print type(line), len(line); \
    sys.stdout.write(line); print line'
  UTF-8
  <type 'unicode'> 2
  Б
  Б

  $ python -c 'import sys, codecs, locale; print sys.stdout.encoding; \
    sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout); \
    line = u"\u0411\n"; print type(line), len(line); \
    sys.stdout.write(line); print line' | cat
  None
  <type 'unicode'> 2
  Б
  Б

На этой странице есть еще немного информации, которую стоит прочитать.

Обновление: Python 3.6 реализует PEP 528. Измените кодировку консоли Windows на UTF-8: консоль по умолчанию в Windows теперь будет принимать все символы Юникода. Внутренне он использует тот же API-интерфейс Unicode, что и win-unicode-console Пакет, упомянутый ниже.print(unicode_string)должен просто работать сейчас.


Я получаюUnicodeEncodeError: 'charmap' codec can't encode character...ошибка.

Ошибка означает, что символы Юникода, которые вы пытаетесь напечатать, не могут быть представлены с использованием текущего (chcp) консольное кодирование символов. Кодовая страница часто представляет собой 8-битную кодировку, такую ​​какcp437которые могут представлять только ~0x100 символов из ~1M символов Юникода:

 >>> u "\ N {EURO SIGN}". закодировать ('cp437')
Traceback (последний вызов был последним):
...
UnicodeEncodeError: кодек 'charmap' не может кодировать символ '\u20ac' в позиции 0:
карты персонажей

Я предполагаю, что это потому, что консоль Windows не принимает символы только для Unicode. Какой лучший способ обойти это?

Консоль Windows принимает символы Юникода и может даже отображать их (только BMP), если настроен соответствующий шрифт.WriteConsoleW()API следует использовать как предложено в ответе @Daira Hopwood. Его можно назвать прозрачным, т. Е. Вам не нужно и не следует изменять свои сценарии, если вы используетеwin-unicode-console пакет:

T:\> py -mpip install win-unicode-console
T:\> py -mrun your_script.py

Посмотрите , как обстоят дела с Python 3.4, Unicode, различными языками и Windows?

Можно ли как-нибудь заставить Python автоматически распечатать?вместо неудачи в этой ситуации?

Если этого достаточно, чтобы заменить все не кодируемые символы? в вашем случае вы могли бы установитьPYTHONIOENCODINGenvvar:

T:\> set PYTHONIOENCODING=:replace
T:\> python3 -c "print(u'[\N{EURO SIGN}]')"
[?]

В Python 3.6+ кодировка указана PYTHONIOENCODING envvar игнорируется для буферов интерактивной консоли, если только PYTHONLEGACYWINDOWSIOENCODING Для envvar задана непустая строка.

Несмотря на другие правдоподобные ответы, которые предлагают изменить кодовую страницу на 65001, это не работает. (Кроме того, изменение кодировки по умолчанию с помощью sys.setdefaultencoding не очень хорошая идея.)

Смотрите этот вопрос для деталей и кода, который работает.

Если вы не заинтересованы в надежном представлении плохих символов, вы можете использовать что-то вроде этого (работа с python >= 2.6, включая 3.x):

from __future__ import print_function
import sys

def safeprint(s):
    try:
        print(s)
    except UnicodeEncodeError:
        if sys.version_info >= (3,):
            print(s.encode('utf8').decode(sys.stdout.encoding))
        else:
            print(s.encode('utf8'))

safeprint(u"\N{EM DASH}")

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

Приведенный ниже код выведет Python на консоль как UTF-8 даже в Windows.

Консоль будет хорошо отображать символы в Windows 7, но в Windows XP она будет отображаться не очень хорошо, но, по крайней мере, она будет работать, и самое главное, вы получите согласованный вывод из своего сценария на всех платформах. Вы сможете перенаправить вывод в файл.

Ниже код был протестирован с Python 2.6 на Windows.


#!/usr/bin/python
# -*- coding: UTF-8 -*-

import codecs, sys

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

print sys.getdefaultencoding()

if sys.platform == 'win32':
    try:
        import win32console 
    except:
        print "Python Win32 Extensions module is required.\n You can download it from https://sourceforge.net/projects/pywin32/ (x86 and x64 builds are available)\n"
        exit(-1)
    # win32console implementation  of SetConsoleCP does not return a value
    # CP_UTF8 = 65001
    win32console.SetConsoleCP(65001)
    if (win32console.GetConsoleCP() != 65001):
        raise Exception ("Cannot set console codepage to 65001 (UTF-8)")
    win32console.SetConsoleOutputCP(65001)
    if (win32console.GetConsoleOutputCP() != 65001):
        raise Exception ("Cannot set console output codepage to 65001 (UTF-8)")

#import sys, codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
sys.stderr = codecs.getwriter('utf8')(sys.stderr)

print "This is an Е乂αmp١ȅ testing Unicode support using Arabic, Latin, Cyrillic, Greek, Hebrew and CJK code points.\n"

Просто введите этот код в командной строке перед выполнением скрипта Python:

chcp 65001 & set PYTHONIOENCODING=utf-8

Как и ответ Джампаоло Родолы, но еще более грязный: я действительно, действительно собираюсь потратить много времени (в ближайшее время) на понимание всего предмета кодировок и того, как они применяются к консолям Windoze,

На данный момент я просто хотел использовать sthg, что означало бы, что моя программа НЕ РАБОТАЕТ, и что я понял... а также что не требует импорта слишком большого количества экзотических модулей (в частности, я использую Jython, так что половину времени Python модуль оказывается фактически не доступен).

def pr(s):
    try:
        print(s)
    except UnicodeEncodeError:
        for c in s:
            try:
                print( c, end='')
            except UnicodeEncodeError:
                print( '?', end='')

NB "pr" короче, чем "print" (и немного короче, чем "safeprint")...!

В некотором роде ответ на вопрос Я. Ф. Себастьяна, но более прямой.

Если у вас возникла эта проблема при печати на консоль / терминал, сделайте следующее:

>set PYTHONIOENCODING=UTF-8

TL;DR:

print(yourstring.encode('ascii','replace'));

Я сам столкнулся с этим, работая над ботом Twitch chat (IRC). (Последняя версия Python 2.7)

Я хотел разобрать сообщения чата, чтобы ответить...

msg = s.recv(1024).decode("utf-8")

но также выведите их на консоль в удобочитаемом формате:

print(msg.encode('ascii','replace'));

Это исправило проблему броска бота UnicodeEncodeError: 'charmap' ошибки и заменил символы Юникода ?,

Для Python 2 попробуйте:

print unicode(string, 'unicode-escape')

Для Python 3 попробуйте:

import os
string = "002 Could've Would've Should've"
os.system('echo ' + string)

Или попробуйте win-unicode-console:

pip install win-unicode-console
py -mrun your_script.py

Причиной вашей проблемы НЕ является консоль Win, которая не желает принимать Unicode (так как это происходит, так как я предполагаю, что Win2k по умолчанию). Это кодировка системы по умолчанию. Попробуйте этот код и посмотрите, что он вам дает:

import sys
sys.getdefaultencoding()

если он говорит ascii, у вас есть причина;-) Вы должны создать файл с именем sitecustomize.py и поместить его в путь к Python (я поместил его в /usr/lib/python2.5/site-packages, но это отличается от Win - это c:\python\lib\site-packages или что-то еще) со следующим содержимым:

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

и, возможно, вы захотите указать кодировку в ваших файлах:

# -*- coding: UTF-8 -*-
import sys,time

Изменить: больше информации можно найти в превосходной книге "Погружение в Python"

В настоящее время консоль Windows не обнаруживает эту ошибку, если вы не перенаправляете вывод.

Вот пример Python-скриптаscratch_1.py:

      s = "∞"

print(s)

Если вы запустите скрипт следующим образом, все будет работать так, как задумано:

      python scratch_1.py
      

Однако, если вы запустите следующее, вы получите ту же ошибку, что и в вопросе:

      python scratch_1.py > temp.txt
      Traceback (most recent call last):
  File "C:\Users\Wok\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_1.py", line 3, in <module>
    print(s)
  File "C:\Users\Wok\AppData\Local\Programs\Python\Python311\Lib\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeEncodeError: 'charmap' codec can't encode character '\u221e' in position 0: character maps to <undefined>

Чтобы решить эту проблему с предложением, присутствующим в исходном вопросе, то есть заменой ошибочных символов вопросительными знаками?, можно поступить следующим образом:

      s = "∞"

try:
    print(s)
except UnicodeEncodeError:
    output_str = s.encode("ascii", errors="replace").decode("ascii")

    print(output_str)

Это важно:

  • звонитьdecode(), так что тип выводаstrвместоbytes,
  • с той же кодировкой, здесь"ascii", чтобы избежать создания моджибаке .

Python 3.6 windows7: есть несколько способов запустить python, вы можете использовать консоль python (на которой есть логотип python) или консоль windows (на ней написано cmd.exe).

Я не мог печатать символы utf8 в консоли Windows. Печать символов utf-8 выдает мне эту ошибку:

OSError: [winError 87] The paraneter is incorrect 
Exception ignored in: (_io-TextIOwrapper name='(stdout)' mode='w' ' encoding='utf8') 
OSError: [WinError 87] The parameter is incorrect 

После попытки понять ответ выше, я обнаружил, что это всего лишь проблема с настройкой. Щелкните правой кнопкой мыши в верхней части окна консоли cmd, на вкладке font выбрал консоль lucida.

Джеймс Сулак спросил,

Есть ли способ, как я могу заставить Python автоматически печатать? вместо неудачи в этой ситуации?

Другие решения рекомендуют попытаться изменить среду Windows или заменить Python print() функция. Ответ ниже приближается к выполнению запроса Сулака.

В Windows 7 Python 3.5 можно заставить печатать Unicode без UnicodeEncodeError следующее:

На месте: print(text)
замена: print(str(text).encode('utf-8'))

Вместо генерирования исключения Python теперь отображает непечатаемые символы Юникода в виде шестнадцатеричных кодов \xNN, например:

Halmalo n \ xe2 \ x80 \ x99 \ xc3 \ xa9tait plus qu \ xe2 \ x80 \ x99un точка нуар

Вместо

Halmalo n'était plus qu'un point noir

Конечно, последний предпочтительнее при прочих равных условиях, но в остальном он абсолютно точен для диагностических сообщений. Поскольку он отображает Unicode в виде буквенных значений байтов, первый также может помочь в диагностике проблем кодирования / декодирования.

Примечание: str() звонок выше нужен потому что иначе encode() заставляет Python отклонять символ Unicode как кортеж чисел.

Проблема заключается в том, что кодировка Windows по умолчанию установлена ​​на cp1252 и должна быть установлена ​​на utf-8. (проверьте PEP)

Проверьте кодировку по умолчанию, используя:

      import locale 
locale.getpreferredencoding()

Вы можете переопределить настройки локали

      import os
if os.name == "nt":
    import _locale
    _locale._gdl_bak = _locale._getdefaultlocale
    _locale._getdefaultlocale = (lambda *args: (_locale._gdl_bak()[0], 'utf8'))

ссылочный код из ссылки стека

Другие вопросы по тегам