Python, Unicode и консоль Windows - PullRequest
       175

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

121 голосов
/ 08 августа 2008

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

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


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

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

Ответы [ 13 ]

66 голосов
/ 24 августа 2015

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


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

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

>>> u"\N{EURO SIGN}".encode('cp437')
Traceback (most recent call last):
...
UnicodeEncodeError: 'charmap' codec can't encode character '\u20ac' in position 0:
character maps to 

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

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

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

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

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

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

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

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

33 голосов
/ 08 августа 2008

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


Вот страница, которая детализирует проблему и решение (найдите на странице текст Упаковка 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
  Б
  Б

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

27 голосов
/ 09 января 2011

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

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

14 голосов
/ 19 мая 2012

Если вы не заинтересованы в надежном представлении плохих символов, вы можете использовать что-то вроде этого (работа с 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.

10 голосов
/ 06 января 2010

Приведенный ниже код выведет 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"
4 голосов
/ 03 октября 2018

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

chcp 65001 & set PYTHONIOENCODING=utf-8
4 голосов
/ 10 марта 2016

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

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

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

Примечание: «pr» короче, чем «print» (и немного короче, чем «safeprint») ...!

3 голосов
/ 24 августа 2017

Для 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
2 голосов
/ 01 июля 2018

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', а символы юникода заменялись ?.

2 голосов
/ 11 августа 2008

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

import sys
sys.getdefaultencoding()

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...