如何使Python 3的print()函数输出UTF-8编码

61

我该如何让Python 3(3.1)print("Some text")输出到标准输出流,并以UTF-8编码输出,或者如何输出原始字节?

Test.py

TestText = "Test - āĀēĒčČ..šŠūŪžŽ" # this is UTF-8
TestText2 = b"Test2 - \xc4\x81\xc4\x80\xc4\x93\xc4\x92\xc4\x8d\xc4\x8c..\xc5\xa1\xc5\xa0\xc5\xab\xc5\xaa\xc5\xbe\xc5\xbd" # just bytes
print(sys.getdefaultencoding())
print(sys.stdout.encoding)
print(TestText)
print(TestText.encode("utf8"))
print(TestText.encode("cp1252","replace"))
print(TestText2)

输出结果(使用CP1257编码,我将字符替换为字节值[x00]):

utf-8
cp1257
Test - [xE2][xC2][xE7][C7][xE8][xC8]..[xF0][xD0][xFB][xDB][xFE][xDE]  
b'Test - \xc4\x81\xc4\x80\xc4\x93\xc4\x92\xc4\x8d\xc4\x8c..\xc5\xa1\xc5\xa0\xc5\xab\xc5\xaa\xc5\xbe\xc5\xbd'
b'Test - ??????..\x9a\x8a??\x9e\x8e'
b'Test2 - \xc4\x81\xc4\x80\xc4\x93\xc4\x92\xc4\x8d\xc4\x8c..\xc5\xa1\xc5\xa0\xc5\xab\xc5\xaa\xc5\xbe\xc5\xbd'

print太聪明了... :D 使用编码文本与print没有意义(因为它始终只显示字节的表示而不是实际字节),并且根本无法输出字节,因为print总是将其编码为sys.stdout.encoding

例如:print(chr(255))会抛出错误:

Traceback (most recent call last):
  File "Test.py", line 1, in <module>
    print(chr(255));
  File "H:\Python31\lib\encodings\cp1257.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\xff' in position 0: character maps to <undefined>
顺便说一下,print(TestText == TestText2.decode(“utf8”)) 返回 False,尽管打印输出相同。
Python 3 如何确定 sys.stdout.encoding,我该如何更改它?
我创建了一个 printRAW() 函数,它运行良好(实际上它将输出编码为 UTF-8,因此它并不是原始的...):
 def printRAW(*Text):
     RAWOut = open(1, 'w', encoding='utf8', closefd=False)
     print(*Text, file=RAWOut)
     RAWOut.flush()
     RAWOut.close()

 printRAW("Cool", TestText)

输出(现在以UTF-8格式打印):

Cool Test - āĀēĒčČ..šŠūŪžŽ

printRAW(chr(252)) 也可以很好地打印出 ü(在UTF-8中,[xC3][xBC]),而且没有错误 :)

现在我正在寻找更好的解决方案,如果有的话...


也请查看这个链接:https://dev59.com/a1kS5IYBdhLWcg3wu4rL。 - Soorena
TestText以“Test”开头,而TestText2以“Test2”开头,因此它们不会相等:D - Philippe Carphin
5个回答

68

澄清:

TestText = "Test - āĀēĒčČ..šŠūŪžŽ" # this not UTF-8...it is a Unicode string in Python 3.X.
TestText2 = TestText.encode('utf8') # this is a UTF-8-encoded byte string.

要发送UTF-8至标准输出而不考虑控制台的编码,请使用其缓冲区接口,该接口接受字节:

import sys
sys.stdout.buffer.write(TestText2)

1
我得到了以下错误信息:Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: '_ReplOutput' 对象没有 'buffer' 属性。 - o17t H1H' S'k
Python 3?你在使用集成开发环境吗?_ReplOutput听起来像是标准输出被替换为(不正确的)文件对象。 - Mark Tolonen
@VanJone,请发布一个新问题。 - Mark Tolonen
@Mark,也许我在上一条评论中没有表达清楚,答案并不总是有效的,就像在我的情况下一样,所以我发布了这个错误消息。我根本没有问任何问题。 - Van Jone
是的,它适用于字节字符串,所以你的第二个理由是100%正确的。 - Van Jone
显示剩余4条评论

16

这是我从手册中能够推断出的最佳方法,但它有点不太正规:

utf8stdout = open(1, 'w', encoding='utf-8', closefd=False) # fd 1 is stdout
print(whatever, file=utf8stdout)

看起来文件对象应该有一个改变它们编码的方法,但据我所知并没有。

如果你先写入 utf8stdout ,然后再写入 sys.stdout 而没有先调用 utf8stdout.flush() ,或者反过来,可能会发生糟糕的事情。


5
在Windows上遇到问题,打印时使用了cp1257(导致失败),而我想要使用utf-8。以下代码片段可以解决:import sys; sys.stdout = open(1, 'w', encoding='utf-8', closefd=False); print("vadsэавфыаЭХÜÜÄ"); print(bytes("аЭХÜ", "utf-8")) - iljau
@zwol和所有人:Python 3的print函数被定义和设计为不处理Unicode的原因是什么? - Old Geezer
@OldGeezer 这不正确。它曾经被定义和设计为处理Unicode。但解释器认为,由于某些我们可能永远不会知道的原因,sys.stdout正在输入到一个只处理CP1257而不是Unicode的终端仿真器中,因此print(实际上是sys.stdout.write)必须在打印之前将Unicode转换为CP1257,并且任何不在CP1257字符集中的字符都无法打印(除非首先进行转义,但print不会为您执行此操作)。 - zwol

12
根据这篇回答
自Python 3.7起,您可以手动重新配置stdout的编码。
import sys
sys.stdout.reconfigure(encoding='utf-8')

1
我尝试了zwol's solution在Python 3.6中,但它对我不起作用。 对于某些字符串,没有输出到控制台。
但是iljau's solution有效:使用不同的编码重新打开stdout。
import sys
sys.stdout = open(1, 'w', encoding='utf-8', closefd=False)

0

您可以使用以下代码将控制台编码设置为 utf-8:

import sys
sys.stdout = open(sys.stdout.fileno(), mode='w', encoding='utf8', buffering=1)

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