Python、 Unicode 和 Windows 控制台

当尝试在 Windows 控制台中打印 Unicode 字符串时,会得到一个错误。

UnicodeEncodeError: 'charmap' codec can't encode character ....

我假设这是因为 Windows 控制台不接受仅 Unicode 字符。解决这个问题的最好方法是什么? 有没有什么办法可以让 Python 自动打印 ?而不是在这种情况下失败?

编辑: 我正在使用 Python 2.5。


注意: @LasseV. Karlsen 带有勾号的回答有点过时(自2008年起)。请谨慎使用下面的解决方案/回答/建议!

@ JFSebastian 的回答截至今日(2016年1月6日)更为贴切。

125673 次浏览

注意: 此答案有点过时(自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
Б
Б

那页上还有更多信息,值得一读。

你的问题的原因是 没有的赢控制台不愿意接受 Unicode (因为它这样做,因为我猜 Win2k 默认)。这是默认的系统编码。试试这段代码,看看它能给你带来什么:

import sys
sys.getdefaultencoding()

如果上面写着 ascii,那就是你的理由; -) 你必须创建一个名为 sitecustomize.py 的文件,并把它放在 python 路径下(我把它放在/usr/lib/python2.5/site-package 下,但是在 Win 上不一样——它是 c: python lib site-package 或者别的什么) ,包含以下内容:

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

也许您还想在文件中指定编码方式:

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

编辑: 更多信息可以找到 在优秀的《深入 Python 》一书中

下面的代码将使 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"

更新: 在 Python 3.6或更高版本上,在 Windows 控制台上打印 Unicode 字符串就可以了。

所以,升级到最近的 Python 就可以了。在这一点上,我建议使用2to3在需要时将代码更新为 Python 3.x,并放弃对 Python 2.x 的支持。请注意,在3.7(包括 Python 2.7) 从2021年12月开始之前,对任何版本的 Python 都没有安全支持。

如果 真的仍然需要支持 Python 的早期版本(包括 Python 2.7) ,那么可以使用基于 https://github.com/Drekin/win-unicode-console的 API,并使用与答案中的代码相同的 API,即 前情提要。(该链接确实包含一些关于 Windows 字体配置的信息,但我怀疑它仍然适用于 Windows8或更高版本。)

注意: 尽管其他貌似合理的答案建议将代码页更改为65001,但 在 Python 3.8之前不能工作。(从那时起,它就开始工作了,但是正如上面所指出的,对于 Python 3.6 + ,无论如何都不需要这样做。)此外,使用 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 3.6实现 PEP 528: 将 Windows 控制台编码更改为 UTF-8: Windows 上的默认控制台现在将接受所有 Unicode 字符。在内部,它使用与 下面提到的 win-unicode-console软件包相同的 Unicode API。


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

该错误意味着您试图打印的 Unicode 字符无法使用当前(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) 如果配置了相应的字体。应该按照 @ Daira Hopwood 的回答中的建议使用 WriteConsoleW() API。它可以被称为透明的,也就是说,如果你使用 win-unicode-console包裹,你不需要也不应该修改你的脚本:

T:\> py -m pip install win-unicode-console
T:\> py -m run your_script.py

参见 Python 3.4、 Unicode、不同的语言和 Windows 是怎么回事?

有没有办法让巨蟒 自动打印 ?而不是在这种情况下失败?

如果在您的情况下,用 ?替换所有不可编码的字符就足够了,那么您可以设置 PYTHONIOENCODING envar:

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

在 Python 3.6 + 中,交互式控制台缓冲区忽略 PYTHONIOENCODING envvar 指定的编码,除非将 PYTHONLEGACYWINDOWSIOENCODING envvar 设置为非空字符串。

和 J · F · 塞巴斯蒂安的答案有关,但更直接。

如果在打印到控制台/终端时遇到此问题,请执行以下操作:

>set PYTHONIOENCODING=UTF-8

就像 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='')

注意“ pr”比“ print”短(而且比“ safeprint”短得多) ... !

詹姆斯 · 苏拉克问道,

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

其他解决方案建议我们尝试修改 Windows 环境或替换 Python 的 print()函数。下面的答案更接近于满足苏拉克的要求。

在 Windows 7下,Python 3.5可以在不抛出 UnicodeEncodeError的情况下打印 Unicode,如下所示:

取代: print(text)
替代品: print(str(text).encode('utf-8'))

Python 现在不再抛出异常,而是将不可打印的 Unicode 字符显示为 XNN十六进制代码,例如:

Halmalo 2 x80 x99 xc3 xa9再加上2 x80 x99 un 黑点

而不是

Halmalo 不过是个黑点

当然,后者更适合于 在其他条件不变的情况下,但是在其他情况下,前者对于诊断消息是完全准确的。因为它将 Unicode 显示为文字字节值,所以前者也可能有助于诊断编码/解码问题。

注意: 需要上面的 str()调用,因为否则 encode()会导致 Python 拒绝将 Unicode字符作为数字元组。

Python 3.6 windows7: 有几种方法可以启动一个 Python,你可以使用 Python 控制台(上面有一个 Python 徽标)或者 windows 控制台(上面写着 cmd.exe)。

我无法在 Windows 控制台中打印 utf8字符。打印 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 2,请尝试:

print unicode(string, 'unicode-escape')

对于 Python 3,请尝试:

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

或者试试 win-unicode-sole:

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

译者:

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

我自己在使用 Twitch chat (IRC)聊天机器人时遇到了这个问题

我想解析聊天信息,以便响应..。

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

而且还能以人类可读的格式安全地打印到控制台上:

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

这纠正了 bot 抛出 UnicodeEncodeError: 'charmap'错误的问题,并将 unicode 字符替换为 ?

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

chcp 65001 & set PYTHONIOENCODING=utf-8

问题是 windows 默认编码被设置为 cp1252,并且需要被设置为 utf-8

使用以下方法检查默认编码:

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'))

来自 堆栈链接的引用代码

现在,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",以避免产生 鸡尾酒