字符编码
1. 字符编码简介:
1.1. ASCII 1.2. MBCS 1.3. Unicode主要研究
2. Python2.x中的编码问题:
2.1. str和unicode:
str和unicode都是basestring的子类。严格意义上说,str其实是字节串,它是unicode经过编码后的字节组成的序列。对UTF-8编码的str'汉'使用len()函数时,结果是3,因为实际上,UTF-8编码的'汉' == 'xE6xB1x89'。
unicode才是真正意义上的字符串,对字节串str使用正确的字符编码进行解码后获得,并且len(u'汉') == 1。
再来看看encode()和decode()两个basestring的实例方法,理解了str和unicode的区别后,这两个方法就不会再混淆了:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# coding: UTF-8 u = u'汉' print repr(u) # u'u6c49' s = u.encode('UTF-8') print repr(s) # 'xe6xb1x89' u2 = s.decode('UTF-8') print repr(u2) # u'u6c49' # 对unicode进行解码是错误的 # s2 = u.decode('UTF-8') # 同样,对str进行编码也是错误的 # u2 = s.encode('UTF-8') |
需要注意的是,虽然对str调用encode()方法是错误的,但实际上Python不会抛出异常,而是返回另外一个相同内容但不同id的str;对unicode调用decode()方法也是这样。很不理解为什么不把encode()和decode()分别放在unicode和str中而是都放在basestring中,但既然已经这样了,我们就小心避免犯错吧
2.2. 字符编码声明
源代码文件中,如果有用到非ASCII字符,则需要在文件头部进行字符编码的声明,如下:
1
#-*- coding: UTF-8 -*-
实际上Python只检查#、coding和编码字符串,其他的字符都是为了美观加上的。另外,Python中可用的字符编码有很多,并且还有许多别名,还不区分大小写,比如UTF-8可以写成u8。参见http://docs.python.org/library/codecs.html#standard-encodings。
另外需要注意的是声明的编码必须与文件实际保存时用的编码一致,否则很大几率会出现代码解析异常。现在的IDE一般会自动处理这种情况,改变声明后同时换成声明的编码保存,但文本编辑器控们需要小心 :)
2.3. 读写文件
内置的open()方法打开文件时,read()读取的是str,读取后需要使用正确的编码格式进行decode()。write()写入时,如果参数是unicode,则需要使用你希望写入的编码进行encode(),如果是其他编码格式的str,则需要先用该str的编码进行decode(),转成unicode后再使用写入的编码进行encode()。如果直接将unicode作为参数传入write()方法,Python将先使用源代码文件声明的字符编码进行编码然后写入。
coding: UTF-8 f = open('test.txt') s = f.read() f.close() print type(s) # <type 'str'> # 已知是GBK编码,解码成unicode u = s.decode('GBK') f = open('test.txt', 'w') # 编码成UTF-8编码的str s = u.encode('UTF-8') f.write(s) f.close()
3.一些建议
3.1. 使用字符编码声明,并且同一工程中的所有源代码文件使用相同的字符编码声明
3.2. 抛弃str,全部使用unicode
3.3. 使用codecs.open()替代内置的open()。