这是一个小程序:
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
print('abcd kΩ ☠ °C √Hz µF ü ☃ ♥')
print(u'abcd kΩ ☠ °C √Hz µF ü ☃ ♥')
在Ubuntu,Gnome终端上,IPython做了我期望的事情:
In [6]: run Unicodetest.py
abcd kΩ ☠ °C √Hz µF ü ☃ ♥
abcd kΩ ☠ °C √Hz µF ü ☃ ♥
如果我在trypython.org上输入命令,我会得到相同的输出。
另一方面,codepad.org会对第二个命令产生错误:
abcd kΩ ☠ °C √Hz µF ü ☃ ♥
Traceback (most recent call last):
Line 6, in <module>
print(u'abcd kΩ ☠ °C √Hz µF ü ☃ ♥')
UnicodeEncodeError: 'ascii' codec can't encode character u'\u03a9' in position 6: ordinal not in range(128)
相反,Windows上的IDLE会破坏第一个命令的输出,但不会抱怨第二个命令:
>>>
abcd kΩ ☠°C √Hz µF ü ☃ ♥
abcd kΩ ☠ °C √Hz µF ü ☃ ♥
在Windows命令提示符下或通过Python(x,y)的Console2版本中的IPython都会破坏第一个输出并抱怨第二个输出:
In [9]: run Unicodetest.py
abcd kΩ ☠ °C √Hz µF ü ☃ ♥
ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (15, 0))
---------------------------------------------------------------------------
UnicodeEncodeError Traceback (most recent call last)
Desktop\Unicodetest.py in <module>()
4 print('abcd kΩ ☠ °C √Hz µF ü ☃ ♥')
5
----> 6 print(u'abcd kΩ ☠ °C √Hz µF ü ☃ ♥')
7
8
C:\Python27\lib\encodings\cp437.pyc in encode(self, input, errors)
10
11 def encode(self,input,errors='strict'):
---> 12 return codecs.charmap_encode(input,errors,encoding_map)
13
14 def decode(self,input,errors='strict'):
UnicodeEncodeError: 'charmap' codec can't encode character u'\u2620' in position 8: character maps to <undefined>
WARNING: Failure executing file: <Unicodetest.py>
Python内部的IPython(x,y)的Spyder也是如此,但不同的是:
In [8]: run Unicodetest.py
abcd kΩ ☠°C √Hz µF ü ☃ ♥
------------------------------------------------------------
Traceback (most recent call last):
File "Unicodetest.py", line 6, in <module>
print(u'abcd kΩ ☠°C √Hz µF ü ☃ ♥')
File "C:\Python26\lib\encodings\cp1252.py", line 12, in encode
return codecs.charmap_encode(input,errors,encoding_table)
UnicodeEncodeError: 'charmap' codec can't encode character u'\u03a9' in position 6: character maps to <undefined>
WARNING: Failure executing file: <Unicodetest.py>
(在sitecustomize.py中,Spyder根据语言环境模块的编码设置了自己的SPYDER_ENCODING
,对于Windows 7,这是cp1252
。)
是什么给出的?我的命令之一是错的吗?为什么一个平台在某些平台上运行而另一个平台在其他平台上运行?如何在不崩溃或搞砸的情况下始终如一地打印Unicode字符?
是否有适用于Windows的备用终端,其行为类似于Ubuntu中的终端?似乎TCC-LE,Console2,Git Bash,PyCmd等都只是cmd.exe的包装而不是替换。有没有办法在IDLE使用的接口中运行IPython?
答案 0 :(得分:10)
Python(以及大多数其他语言)中的I / O基于 bytes 。当您将2.x中的字节字符串(str
,3.x中的bytes
)写入文件时,字节简单地按原样写入。当您将2.x中的Unicode字符串(unicode
,3.x中的str
)写入文件时,数据需要编码到字节序列。< / p>
有关此区别的进一步说明,请参阅Dive into Python 3 chapter on strings。
print('abcd kΩ ☠ °C √Hz µF ü ☃ ♥')
这里,字符串是一个字节字符串。因为源文件的编码是UTF-8,所以字节是
'abcd k\xce\xa9 \xe2\x98\xa0 \xc2\xb0C \xe2\x88\x9aHz \xc2\xb5F \xc3\xbc \xe2\x98\x83 \xe2\x99\xa5'
print
语句按原样将这些字节写入控制台。但Windows控制台将字节字符串解释为在“OEM”代码页中编码,在美国437。所以你在屏幕上看到的字符串是
abcd kΩ ☠ °C √Hz µF ü ☃ ♥
在你的Ubuntu系统上,这不会导致问题,因为默认的控制台编码是UTF-8,所以你没有源文件编码和控制台编码之间的差异。
print(u'abcd kΩ ☠ °C √Hz µF ü ☃ ♥')
打印Unicode字符串时,字符串必须将编码转换为字节。但它只有在您拥有支持这些字符的编码时才有效。你没有。
☠☃♥
Ω☠√☃♥
。因此,在这两种情况下,都会遇到尝试打印字符串的UnicodeEncodeError。
是什么给出了?
Windows和Linux采用了截然不同的方法来支持Unicode。
最初,它们的工作方式大致相同:每个语言环境都有自己的语言特定char
编码(Windows中的“ANSI代码页”)。西方语言使用ISO-8859-1或windows-1252,俄语使用KOI8-R或windows-1251等。
当Windows NT添加对Unicode的支持时(在假设Unicode将使用16位字符的早期阶段),它通过创建使用wchar_t
而不是{char
的API的并行版本来实现这一点。 {1}}。例如,MessageBox函数分为两个函数:
int MessageBoxA(HWND hWnd, const char* lpText, const char* lpCaption, unsigned int uType);
int MessageBoxW(HWND hWnd, const wchar_t* lpText, const wchar_t* lpCaption, unsigned int uType);
“W”功能是“真实的”功能。 “A”函数用于向后兼容基于DOS的Windows,并且主要只是将其字符串参数转换为UTF-16,然后调用相应的“W”函数。
在Unix世界(特别是Plan 9)中,编写一个全新版本的POSIX API被认为是不切实际的,因此以不同的方式处理Unicode支持。 CJK语言环境中对多字节编码的现有支持用于实现一种新的编码,现在称为UTF-8。
在编写支持Unicode的跨平台代码时,类Unix系统上的UTF-8和Windows上的UTF-16的偏好是一个巨大的痛苦。 Python试图将其隐藏在程序员之外,但printing to the console是Joel的“漏洞抽象”之一。
答案 1 :(得分:2)
有两个可能的原因:
print
对Unicode进行编码。您无法输出原始Unicode,因此print
需要弄清楚如何将其转换为控制台预期的字节流(它使用sys.stdout.encoding
AFAIK),这将我们带到答案 2 :(得分:0)
你的问题是你的程序期望并输出UTF-8字符,但是网络上的控制台和各种python跑步者使用其他代码页。 无法对所有编码中的特殊字符进行编码而无需修改。但是,如果您选择使用UTF-8 无处不在,那么您应该是安全的。
我认为Windows中的任何终端都会这样做 - 所以不要因为这个而烦恼切换默认终端(cmd.exe)。相反,也要将终端的编码更改为UTF-8,以匹配python脚本的编码。
不幸的是,我从来没有找到过将代码页设置为UTF-8的方法,因此每次打开新的命令提示符时都必须这样做。但它是通过一个简单的命令完成的,所以它只有一半...你用switching codepage更改编码:
>chcp 65001
Current codepage is now 65001
请注意,您必须使用其中一种标准字体才能工作。网络上的大多数消息来源似乎都建议使用Lucida Console。
答案 3 :(得分:0)
从Python到Windows控制台的Unicode输出不起作用。无法说服Python发出需要宽字符和UCS2的本机Windows编码。
答案 4 :(得分:0)
@ dan04:问题是文件的编码与stdout的编码不匹配是对的。然而,解决问题的一种方法是更改文件的编码。因此在Windows上,Notepad ++可用于使用UTF-8字符编码保存代码。
另一种选择是GNU重新编码。