I'm a embedded software engineer! I'm now learning English. and i like photography. I also like Programming with Python, and learning the Turbo Gears! for Web Development!

Showing posts with label Codec. Show all posts
Showing posts with label Codec. Show all posts

Friday, May 04, 2007

the Missing "u": Turbogears tg-admin Shell的unicode问题

利用tg-admin打开shell,

\simpleblog>tg-admin shell
Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
(CustomShell)
>>> unistr = u"你好"
>>> unistr
u'\xc4\xe3\xba\xc3'
>>> import sys
>>> sys.getdefaultencoding()
'ascii'
而直接在Python Command Line(Windows XP,利用Python安装快捷方式,或者Win Console中启动Python)中输入(same with Python2.4 and Python2.5),得到结果却和上面的不一样:

Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> unistr = u"你好"
>>> unistr
u'\u4f60\u597d'

这其中的不同,让我昨天煞是苦恼了一整天:我想在tg-admin shell中输入中文,创建Post对象,用以发布中文Blog。我尝试过在tg-admin shell中进行各种转换,或者在KID的XML()中进行转换,甚至尝试过sys.setdefaultencoding()。可是不管怎么转换,都无法让网页正确的显示中文。


在tg-admin shell中输入u"你好",得到的不是u'\u4f60\u597d'这种真正的Unicode String Object,却是u'\xc4\xe3\xba\xc3'这样已经被UTF-16 Encoding过的String。后来偶然发现,原来tg-admin shell对我输入的中文进行了GB2312编码!此处Python的“u”字符串前缀失去作用了!而且,是GB2312,不是UTF-8!也不是UTF-16!所以我昨天本来尝试对u'\xc4\xe3\xba\xc3'进行UTF-8 Decoding,结果失败了!我怎么也没有想到GB2312,因为TurboGears quickstart生成的框架代码中用的都是UTF-8啊(包括KID的XML编码)!

况且,u'\xc4\xe3\xba\xc3'这一个String本身就是一个很矛盾的东西:外面的’u’说明是unicode字符串,而里面却放的是Byte Coding。

所以无法让tg-admin shell象普通Python Console那样输入。如果要输入Unicode中文,只能通过如下方式:

>>> utf8="你好"
>>> utf8
'\xc4\xe3\xba\xc3'
>>> uni = unicode(utf8, "utf-8")
Traceback (most recent call last):
File "", line 1, in
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 0-1: invalid dat
a
>>> uni = unicode(utf8, "utf-16gb2312")
>>> uni
u'\ue3c4\uc3ba'
注意这里做了一个UTF-8转换的尝试,结果失败了——只能使用GB2312来Decoding。

一开始我还以为tg-admin shell默认做了UTF-16编码!可是没有想到,其实是GB2312!UTF-16确实兼容一些GB2312的编码,但是总归会出现问题的:

>>> utf16 = "这一次我知道了怎么在tg-admin shell中输入中文了"
>>> uni = unicode(utf16, "utf-16")
Traceback (most recent call last):
File "", line 1, in
File "D:\Python25\lib\encodings\utf_16.py", line 16, in decode
return codecs.utf_16_decode(input, errors, True)
UnicodeDecodeError: 'utf16' codec can't decode bytes in position 18-19: illegal
UTF-16 surrogate
>>> uni = unicode(utf16, "utf-8")
Traceback (most recent call last):
File "", line 1, in
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 0-1: invalid dat
a
>>> uni = unicode(utf16, "gb2312")
>>> uni
u'\u8fd9\u4e00\u6b21\u6211\u77e5\u9053\u4e86\u600e\u4e48\u5728tg-admin shell\u4e
2d\u8f93\u5165\u4e2d\u6587\u4e86'
>>>
所以,GB2312才是其中默认的编码方式——这不正是我的电脑当前的编码设置嘛!

那么tg-admin shell中,为何Python的Unicode字符串前缀“u”会失去作用呢??我想我应该去看看tg-admin shell的源代码了。或者,可以从Windows OS的角度去考虑了?

little about Python and Unicode

这里的内容摘录自“All about Python and Unicode
In fact, you should forget all about bytes and think of Unicode strings as sets of symbols.
Unicode objects have no fixed computer representation.

看看下面的示例便知道,Unicode确实只是一种“符号表示”,真正的数据表示应该是'\xNN'这样的一个字节一个字节,所以说Codec做的工作就是这之间的这种转换。
>>> b = repr(uni2)
>>> b"u'\\x1a\\u0bc3\\u1451\\U0001d10c'"
>>> uni2.encode("utf-8")
'\x1a\xe0\xaf\x83\xe1\x91\x91\xf0\x9d\x84\x8c'
>>> print uni2.encode("utf-8")
喁冡憫饾剬
>>> print uni2
Traceback (most recent call last): File "", line 1, in UnicodeEncodeError: 'gbk' codec can't encode character u'\u0bc3' in position 1:illegal multibyte sequence