Python 2.x中的编码问题

在编写python程序,开发python WEB应用时,编码问题是一个绕不开的,并且通常很头疼的问题。一般来说,在开发过程中,python解释器、python编辑器、IDE环境、浏览器、数据库都有各自的编码,要想程序能够正常运行,就必须保证各个部分的编码一致。
现实中存在好多种编码,常用的主要有ASCII、Unicode、UTF-8、以及中文编码GBK。

不同编码的区别

ASCII码

ASCII码是美国标准信息交换码,它用一个字节表示一个英文字符,这样最多可以表示256个字符。ASCII码一共规定了128个字符的编码,比如空格”SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。

非ASCII码

英语用128个字符编码就够了,但是对于其他的非英语的语言来说,128个字符远远不够。比如在法语和西班牙语中,字母上方有注音符号,就无法用ASCII码来表示。于是,一些欧洲国家决定利用一个字节的闲置的最高位编入新的符号,这就最多可以表示256个字符。但是,不同的国家有不同的字母,即使他们都使用一个字节来表示字符,但是同一个数字表示的字母可能不相同。但是不管怎么样,所有这些编码方式中,0-127所表示的字符是一样的,不一样的只是128-255这一段。
至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。比如,简体中文常见的编码方式是GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示256x256=65536个符号。

Unicode码

正如前文所说,不同国家和地区的语言文字使用的编码不尽相同,同一个二进制数字可以被解释为不同的字符。每个国家都使用自己的编码标准,相互之间无法交流。如果有一种统一的编码格式的话,就方便多了。于是,Unicode横空出世。unicod使用一个或多个字节来表示一个字符的方式突破了ASCII码的限制,Unicode可以表示超过90000个字符。需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
这里就有两个严重的问题,第一个问题是,如何才能区别Unicode和ASCII?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果Unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。
它们造成的结果是:1)出现了Unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示Unicode。2)Unicode在很长一段时间内无法推广,直到互联网的出现。

UTF-8码

互联网的出现,强烈要求字符编码的统一。UTF-8是互联网上使用最广的一种unicode编码方式,其他的实现方式还有UTF-16(用两个或四个字节表示字符),UTF-32(用四个字节表示字符)。UTF-8与Unicode的关系是:UTF-8只是一种Unicode的实现方式。
UTF-8的特点:它是一种变长编码方式,使用1~4个字节表示一个字符。
UTF-8编码规则:
- 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
- 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

Python的编码问题

当前系统的默认编码

在安装python时会根据当前系统的默认编码设置自身的编码,使用sys.getdefaultencoding()可以得到当前系统的默认编码。py文件的默认编码是ASCII码。

import sys
print sys.getdefaultencodiing()
#ascii

python 2.x程序文件的编码

在编写python脚本时,可以指定源文件的编码方式。在程序第一行或第二行添加#coding=utf-8,就表示 将字符编码声明为utf-8.需要注意的是声明的编码必须与文件实际保存时用的编码一致,否则很大几率会出现代码解析异常。如果源文件中出现非ASCII码,比如中文注释,要在文件开头声明utf-8编码。

python 2.x中字符串的编码

str和unicode都是basestring的子类。严格意义上讲,str其实是字节串,它是unicode经过编码后的字节组成的序列。对UTF-8编码的str’汉’使用len()函数时,结果是3,因为实际上,UTF-8编码的’汉’ == ‘\xE6\xB1\x89’。
unicode才是真正意义上的字符串,对字节串str使用正确的字符编码进行解码后获得,并且len(u’汉’) == 1。
再来看看encode()和decode()两个basestring的实例方法:

# coding: UTF-8

u = u'汉'
print repr(u) # u'\u6c49'
s = u.encode('UTF-8')
print repr(s) # '\xe6\xb1\x89'
u2 = s.decode('UTF-8')
print repr(u2) # u'\u6c49'

# 对unicode进行解码是错误的
# s2 = u.decode('UTF-8')
# 同样,对str进行编码也是错误的
# u2 = s.encode('UTF-8')

在py文件中输入的字符串,如果没有用Unicode编码,会采用py文件指定的编码来处理,如果py文件中没有指定编码方式,就直接采用系统默认的编码。

import sys
s = '浪潮集团'

这里s中保存的是非ASCII字符串,因为开头没有指定utf-8,程序就按照系统默认编码ASCII来处理,所以会报错。

#-.-coding:utf-8-.-
import sys
s = '浪潮集团'
s1 = u'浪潮集团'
print type(s)      #<typr 'str'>
print type(s1)    #<typr 'unicode'>
s = s.decode('utf-8')
print type(s)      #<type 'unicode'>

这里在程序开头指定了utf-8编码,就会用utf-8来处理s,所以不会产生错误。
可以看出,直接手动输入的字符创类型是’str’,其具体编码格式则由系统或者源文件中指定的编码方式确定。而使用u’浪潮集团’显式定义的字符串类型则是unicode。python中unicode就像一个转换器,不同编码格式的str转换要通过unicode。

s.decode('code_A').encode('code_B')    #s是code_A编码的str
  • 从str转unicode要用decode方法;
  • 从unicode转str要用encode方法;
  • str的编码是与系统环境相关的;
  • 不同编码转换,使用unicode作为中间编码;

python读写文件时的编码

内置的open()方法打开文件时,read()读取的是str,读取后需要使用正确的编码格式进行decode()。
write()写入时,如果参数是unicode,则需要使用你希望写入的编码进行encode(),如果是其他编码格式的str,则需要先用该str的编码进行decode(),转成unicode后再使用写入的编码进行encode()。
如果直接将unicode作为参数传入write()方法,Python将先使用源代码文件声明的字符编码进行编码然后写入。
把python看做一个水池,一个入口,一个出口
入口处,全部转成unicode, 池里全部使用unicode处理,出口处,再转成目标编码

s = u'浪潮集团'
s = s.encode('utf-8')
fp = open('test.txt','w')
fp.write(s)
fp.close

模块codecs提供了一个open()方法,可以指定一个编码打开文件,使用这个方法打开的文件读取返回的将是unicode。写入时,如果参数是unicode,则使用open()时指定的编码进行编码后写入;如果是str,则先根据源代码文件声明的字符编码,解码成unicode后再进行前述操作。

import codecs
s = u'浪潮集团'
fp = codecs.open('test.txt','w')
fp.write(s)
fp.close

以上两种方法都可以处理python读写文件编码错误的问题。

参考资料:

PYTHON编码处理-str与Unicode的区别:http://www.mamicode.com/info-detail-308445.html
Python字符编码详解:http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html
ASCII、Unicode、GBK和UTF-8字符编码的区别联系:http://dengo.org/archives/901

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值