如何在Python 3.0中使print()输出UTF-8?

18

我正在WinXP 5.1.2600上工作,编写一个涉及中文拼音的Python应用程序,这让我陷入了无尽的Unicode问题。转换到Python 3.0已经解决了其中很多问题。但是控制台输出的print()函数由于某种奇怪的原因不支持Unicode。下面是一个微小的程序。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
    
import sys

print('sys.stdout encoding is "' + sys.stdout.encoding + '"')
str1 = 'lüelā'
print(str1)

输出为(为了可读性将角括号更改为方括号):
    sys.stdout 编码为 "cp1252"
    Traceback (most recent call last):
      File "TestPrintEncoding.py", line 22, in [模块]
        print(str1)
      File "C:\Python30\lib\io.py", line 1491, in write
        b = encoder.encode(s)
      File "C:\Python30\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 '\u0101' 
    in position 4: character maps to [undefined]

请注意,ü = '\xfc' = 252 没有问题,因为它是高ASCII。但是 ā = '\u0101' 超出了8位。

有人知道如何将 sys.stdout 的编码更改为 'utf-8' 吗?请记住,如果我正确理解文档,Python 3.0 不再使用 codecs 模块。


(请注意,“coding:”行指定的编码是源代码的编码,而不是控制台输出的编码。但感谢您的想法!)

5个回答

15

7
如果您使用可以显示所需Unicode字符的字体,并更改代码页为UTF-8(可以使用CHCP 65001实现),则cmd.exe可以显示Unicode字符。 - smerlin
那并不是很可靠...此外,MSDN建议使用UTF-16,这是所有Windows NT操作系统的本地编码。 - dom0
@csde_rats他们不是使用旧的、固定宽度的UCS-2而不是UTF-16吗? - Kos
是的和不是的。没有和有的。微软很久以前使用UCS-2,但在某个时候转向了UTF-16。仍然有一些函数与UTF-16不太兼容,特别是在内核方面... - dom0

12

2

请参考这里的问题和答案,我认为它们提供了一些有价值的线索。特别要注意sys模块中的setdefaultencoding,但也要注意不要使用它。


1
Python在Windows中显示Unicode字符的问题是众所周知的。目前还没有官方解决方案。正确的做法是使用winapi函数WriteConsoleW。构建一个可行的解决方案并不容易,因为存在其他相关问题。然而,我开发了一个包来尝试解决Python中的这个问题。请参见https://github.com/Drekin/win-unicode-console以获取更深入的问题解释。该软件包也在pypi上(https://pypi.python.org/pypi/win_unicode_console),可以使用pip进行安装。

点赞,py -mpip install win-unicode-console & py -mrun your_script.py 是在 Python 3 上使用 cmd.exe 打印 Unicode 到 Windows 控制台的解决方案(确保您已为控制台窗口配置了适当的字体)。 - jfs
@J.F.Sebastian,现在认为使用run是次优的。当我不知道自定义readline钩子时,需要使用runwin_unicode_console.enable()就足够了,并且可以将其放入sitecustomize中,以便自动运行。然后您可以像往常一样运行脚本:py your_script.py - user87690
我不想在我的脚本中使用win-unicode-console代码(py -mrun允许我这样做)。我经常在Unix上的Python 2上运行相同的脚本,其中print(unicode_text)可以正常工作。修改sitecustomize模块对我来说太过侵入性。它可能会影响无关的代码。为了将输出重定向到文件,我设置了PYTHONIOENCODING并运行py your_script.py > output.txt - jfs

1
这是一个不太正规的解决方法:
# works
import os
os.system("chcp 65001 &")
print("юникод")

然而,一切都会破坏它:

  • simple muting first line already breaks it:

    # doesn't work
    import os
    os.system("chcp 65001 >nul &")
    print("юникод")
    
  • checking for OS type breaks it:

    # doesn't work
    import os
    if os.name == "nt":
        os.system("chcp 65001 &")
    
    print("юникод")
    
  • it doesn't even works under if block:

    # doesn't work
    import os
    if os.name == "nt":
        os.system("chcp 65001 &")
        print("юникод")
    
但是可以使用cmd的echo命令打印输出:
# works
import os
os.system("chcp 65001 & echo {0}".format("юникод"))

这里有一种简单的方法可以使其跨平台:

# works

import os

def simple_cross_platrofm_print(obj):
    if os.name == "nt":
        os.system("chcp 65001 >nul & echo {0}".format(obj))
    else:
        print(obj)

simple_cross_platrofm_print("юникод")

但是窗口的echo会有一个无法消除的空行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接