Python,Unicode和Windows控制台

Jam*_*lak 128 python unicode

当我尝试在Windows控制台中打印Unicode字符串时,出现UnicodeEncodeError: 'charmap' codec can't encode character ....错误.我认为这是因为Windows控制台不接受仅Unicode字符.最好的方法是什么??在这种情况下,有什么方法可以让Python自动打印而不是失败?

编辑: 我正在使用Python 2.5.


注意: @ LasseV.Karlsen回答带有复选标记有点过时(从2008年开始).请谨慎使用下面的解决方案/答案/建议!!

截至今天(2016年1月6日),@ JFSebastian答案更为相关.

jfs*_*jfs 70

更新: Python 3.6实现PEP 528:将Windows控制台编码更改为UTF-8:Windows上的默认控制台现在将接受所有Unicode字符.在内部,它使用与下面提到win-unicode-console相同的Unicode API .print(unicode_string)应该现在就开始工作.


我收到一个UnicodeEncodeError: 'charmap' codec can't encode character... 错误.

该错误意味着您尝试打印的Unicode字符无法使用current(chcp)控制台字符编码表示.代码页通常是8位编码,例如,cp437它只能表示来自〜1M Unicode字符的~0x100个字符:

>>> 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控制台确实接受Unicode字符,如果配置了相应的字体,它甚至可以显示它们(仅限BMP).WriteConsoleW()应该按照@Daira Hopwood的回答中的建议使用API .它可以透明地调用,即如果使用win-unicode-console,则不需要也不应该修改脚本:

T:\> py -mpip install win-unicode-console
T:\> py -mrun your_script.py
Run Code Online (Sandbox Code Playgroud)

请参阅Python 3.4,Unicode,不同语言和Windows有什么用?

?在这种情况下,有什么方法可以让Python自动打印而不是失败?

如果足以?在您的情况下替换所有不可编码的字符,那么您可以设置PYTHONIOENCODINGenvvar:

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

在Python 3.6+中,PYTHONIOENCODING除非将PYTHONLEGACYWINDOWSIOENCODINGenvvar设置为非空字符串,否则将忽略envvar 指定的编码以用于交互式控制台缓冲区.

  • “ Windows上的默认控制台现在将接受所有Unicode字符” **但是**您需要配置控制台:右键单击窗口顶部(cmd或python IDLE),以默认/字体选择“ Lucida控制台”。(日语和中文对我不起作用,但没有它我应该生存…) (2认同)
  • @Guillaume:答案包含有关Windows控制台的粗体字样的短语:*“如果配置了相应的字体。” *此答案未提及IDLE,但您无需在其中配置字体(我可以看到默认情况下,IDLE中的日文和中文字符都很好,请尝试使用`print('\ u4E01')`,`print('\ u6b63')`)。 (2认同)
  • @Guillaume如果在Windows 10中安装语言包,您甚至可以获得中文.它添加了支持中文的控制台字体. (2认同)

ang*_*son 36

注意:这个答案有点过时(从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
  ?
  ?
Run Code Online (Sandbox Code Playgroud)

有关该页面的更多信息,非常值得一读.

  • 链接已经死了,答案的主旨没有引用.-1 (7认同)
  • 链接已经死了.代码示例对于Windows控制台是错误的,其中代码页(OEM)(例如`cp437`)与Windows ANSI代码页(例如`cp1252`)不同.代码没有修复`UnicodeEncodeError:'charmap'编解码器无法编码字符`错误并可能导致mojibake,例如,`ا©`默默地替换为`╪º⌐`. (2认同)

Dai*_*ood 27

尽管有其他看似合理的答案建议将代码页更改为65001,但这不起作用.(此外,使用更改默认的编码sys.setdefaultencoding不是一个好主意.)

有关详细信息和可行的代码,请参阅此问题.

  • `win-unicode-console` Python包(基于你的代码)允许在使用[`py -mrun your_script.py`命令]直接打印Unicode时避免修改脚本(http://stackoverflow.com/a/32176732/4279). (2认同)

Gia*_*olà 14

如果你对获得可靠的坏字符表示不感兴趣,可以使用类似的东西(使用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}")
Run Code Online (Sandbox Code Playgroud)

字符串中的错误字符将以Windows控制台可打印的表示形式进行转换.

  • 这是极大的,*惊人的*错误。编码为 UTF-8 然后解码为 8 位字符集将 a) 经常失败,并非所有代码页都具有所有 256 字节值的字符,并且 b) *总是* 对数据的错误解释,产生 [Mojibake](https ://en.wikipedia.org/wiki/Mojibake) 来代替。 (4认同)

sor*_*rin 10

下面的代码将使Python输出到控制台,即使在Windows上也是UTF-8.

控制台将在Windows 7上很好地显示字符,但在Windows XP上它将无法很好地显示它们,但至少它将起作用,最重要的是,您将在所有平台上从脚本获得一致的输出.您将能够将输出重定向到文件.

下面的代码在Windows上使用Python 2.6进行了测试.


#!/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"
Run Code Online (Sandbox Code Playgroud)

  • 不要更改系统默认编码; 修改你的Unicode值.更改默认编码可能会破坏依赖于*默认行为*的库.在执行此操作之前,您必须强制重新加载模块. (3认同)

mik*_*ent 6

就像 Giampaolo Rodolà 的回答一样,但更肮脏:我真的,真的打算花很长时间(很快)了解编码的整个主题以及它们如何应用于 Windoze 控制台,

目前我只想要 sthg 这意味着我的程序不会崩溃,而且我理解......而且它不涉及导入太多外来模块(特别是我使用的是 Jython,所以有一半的时间是 Python模块实际上并不可用)。

def pr(s):
    try:
        print(s)
    except UnicodeEncodeError:
        for c in s:
            try:
                print( c, end='')
            except UnicodeEncodeError:
                print( '?', end='')
Run Code Online (Sandbox Code Playgroud)

注意“pr”比“print”更短(并且比“safeprint”更短)......!


小智 6

只需在执行 python 脚本之前在命令行中输入此代码:

chcp 65001 & set PYTHONIOENCODING=utf-8
Run Code Online (Sandbox Code Playgroud)