帮我理解为什么Unicode在Python中只能有时候起作用

19 浏览
0 Comments

帮我理解为什么Unicode在Python中只能有时候起作用

这是一个小程序:\n

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
print('abcd kΩ  °C √Hz µF ü  ')
print(u'abcd kΩ  °C √Hz µF ü  ')

\n在Ubuntu的Gnome终端上,IPython的表现符合我的期望:\n

In [6]: run Unicodetest.py
abcd kΩ  °C √Hz µF ü  
abcd kΩ  °C √Hz µF ü  

\n如果我在trypython.org上输入这些命令,我会得到相同的输出。\n而codepad.org则对第二个命令产生错误:\n

abcd kΩ  °C √Hz µF ü  
Traceback (most recent call last):
  Line 6, in 
    print(u'abcd kΩ  °C √Hz µF ü  ')
UnicodeEncodeError: 'ascii' codec can't encode character u'\u03a9' in position 6: ordinal not in range(128)

\n相反,Windows上的IDLE会破坏第一个命令的输出,但对第二个命令不会报错:\n

>>>
abcd kΠ☠ °C √Hz µF ü ☃ â¥
abcd kΩ  °C √Hz µF ü  

\nWindows命令提示符中的IPython或Python(x,y)的Console2版本会破坏第一个输出并报错第二个:\n

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 ()
      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 
WARNING: Failure executing file: 

\nPython(x,y)的Spyder中的IPython也会产生相同的错误,但方式不同:\n

In [8]: run Unicodetest.py
abcd kΠ☠ °C √Hz µF ü ☃ â¥
------------------------------------------------------------
Traceback (most recent call last):
  File "Unicodetest.py", line 6, in 
    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 
WARNING: Failure executing file: 

\n(在sitecustomize.py中,Spyder根据locale模块的编码设置了自己的SPYDER_ENCODING,Windows 7上为cp1252。)\n这是怎么回事?我哪个命令写错了吗?为什么一个在某些平台上工作而另一个在其他平台上工作?如何稳定地打印Unicode字符而不崩溃或损坏输出?\n有没有一个在Windows上像Ubuntu上的那个终端一样的替代品?看起来TCC-LE、Console2、Git Bash、PyCmd等都只是cmd.exe的封装而不是替代品。有没有办法在IDLE使用的界面中运行IPython?

0
0 Comments

帮助我理解为什么Python只在某些情况下使用Unicode能正常工作

问题出现的原因是程序期望和输出UTF-8字符,但控制台和各种网络上的Python运行器使用其他代码页。如果不进行修改,没有办法在所有编码中编写可正常工作的特殊字符。然而,如果选择在所有地方都使用UTF-8,应该是安全的。

我认为Windows中的任何终端都可以使用,所以不要因为这个问题而更换默认终端(cmd.exe)。相反,将终端的编码设置为UTF-8,以便与Python脚本的编码匹配。

不幸的是,我从来没有找到一种将代码页设置为UTF-8的默认方式,所以每次打开新的命令提示符时都必须进行设置。但是它通过一个简单的命令完成,所以还算不错...你可以通过切换代码页来改变编码:

>chcp 65001

当前代码页已更改为65001

请注意,你必须使用标准字体之一才能使其正常工作。大多数网络上的来源似乎建议使用Lucida Console。

现在,我尝试的每个命令都失败并显示"LookupError: unknown encoding: cp65001",这是由于在"C:\Python27\lib\site-packages\IPython\iplib.pyc"中的"line = raw_input_original(prompt).decode(self.stdin_encoding)"引起的。

不幸的是,chcp 65001存在许多问题。Microsoft C运行时和默认的Windows控制台都设计为与特定区域设置的代码页配合使用;当其他人都在使用UTF-8作为一切的编码时,这是一种真正的遗憾。

0
0 Comments

Python中Unicode只在某些情况下工作的原因是由于以下两个可能的原因:

1. 通过print对Unicode进行编码。不能直接输出原始的Unicode,所以print需要确定如何将其转换为控制台所期望的字节流(它使用sys.stdout.encoding),这就涉及到了:

2. 控制台的支持。Python无法控制你的终端,因此如果它输出的是UTF-8,而你的终端期望的是其他编码,你将得到乱码输出。

为了解决这个问题,可以尝试以下方法:

1. 确保在使用print输出Unicode之前,先将其正确地编码为控制台所期望的字节流。可以使用unicode.encode方法来实现这一点,例如:print(unicode.encode('utf-8'))

2. 确保终端支持Unicode编码,可以通过设置终端的编码方式为UTF-8来解决这个问题。具体的设置方法取决于你使用的终端类型和操作系统。

通过解决上述两个问题,就可以确保Python中的Unicode在所有情况下正常工作。

0
0 Comments

帮助我理解为什么Unicode在Python中有时候只能部分工作的原因。

在Python中,I/O(以及大多数其他编程语言)是基于字节的。当你将一个字节字符串(2.x版本中的str,3.x版本中的bytes)写入文件时,字节会按原样写入。当你将一个Unicode字符串(2.x版本中的unicode,3.x版本中的str)写入文件时,数据需要被编码为一个字节序列。

进一步解释这个区别的说明可以参见“Dive into Python 3”中关于字符串的章节。

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字符串时,字符串需要被编码为字节。但是只有当你有一个支持这些字符的编码时才能正常工作。而你没有。

- 默认的IBM437编码缺少字符``

- Spyder使用的windows-1252编码缺少字符`Ω√`

所以,在这两种情况下,尝试打印这个字符串会导致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的平行版本来实现。例如,`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的新编码。

Unix-like系统对UTF-8的偏好以及Windows对UTF-16的偏好在编写支持Unicode的跨平台代码时是一个巨大的麻烦。Python试图将这一点隐藏在程序员面前,但在控制台打印是Joel的“泄露抽象”的一个例子。

非常有帮助,谢谢。我仍然想知道在Windows的IPython中是否有办法使"print"工作,无论是在内置的Windows控制台中还是在其他第三方控制台中(如果有这样的控制台存在的话)。如果无法显示特殊字符,我希望至少能打印"?"或其他不会崩溃的东西。

是的,Notepad++可以保存为UTF-8,但这似乎不是问题所在。问题是文件的编码与标准输出的编码不匹配。

如果一个模块输出像`u'G\xc3\xb6teborg, Sweden'`这样的字符串,这是不正确的吗?它应该是`u'G\xf6teborg, Sweden'`,或者在编码为UTF-8之后是`'G\xc3\xb6teborg, Sweden'`而不带有`u`。

我相信是的,解决方法是`u'G\xc3\xb6teborg, Sweden'.encode('raw_unicode_escape')` → `'G\xc3\xb6teborg, Sweden'`

0