python字符编码使用什么编码,Python编码方式
本文主要介绍一篇深入了解Python字符编码的文章,各种常用字符编码的特点,以及如何对抗python2.x中的编码问题以下关于需要的朋友可以参考的细节。
00-1010 1.字符编码介绍1.1。ASCII 1.2。MBCS 1.3。unicode 2。Python 2.X .编码问题2.1。字符串和unicode2.2 .字符编码语句2.3。读写文件2.4。编码相关方法3。建议3.1。字符编码语句3.2。放弃str并使用Unicode all。3.3.使用codecs.open()而不是内置的open()。3.4.绝对需要避免的字符编码:MBCS/DBCS和UTF-16。
目录
1. 字符编码简介
ASCII(美国信息交换标准代码)是一种单字节代码。起初,计算机世界里只有英文,但一个字节可以代表256个不同的字符,全是英文字符和许多控制符号。但是,ASCII只使用其中的一半(低于\x80),这是MBCS的基础。
1.1. ASCII
然而,其他语言将很快出现在计算机世界中,单字节ASCII已经不能满足需求。后来,每种语言都发展出自己的代码。因为单个单词表示的字符太少,同时又需要兼容ASCII码,所以这些码已经用多个字节来表示字符,比如GBxxx,BIGxxx等。他们的规则是,如果第一个字节在\x80以下,仍然代表ASCII字符;如果大于\x80,则与下一个字节(共两个字节)一起表示一个字符,然后跳过下一个字节继续判断。
在这里,IBM发明了一个叫做代码页的概念,它包含了所有这些代码并分配了页码。GBK是936页,也就是CP936。因此,CP936也可以用来代表GBK。
MBCS(多字节字符集)是这些代码的总称。到目前为止,每个人都使用双字节,所以它有时被称为DBCS(双字节字符集)。必须明确的是,MBCS不是一个特定的代码。在Windows中,MBCS根据你设置的地区引用不同的代码,而在Linux中,MBCS不能作为代码。你在Windows里看不到MBCS这几个字,因为微软为了更洋气,用ANSI吓唬人。记事本的“另存为”对话框中的代码ANSI是MBCS。同时,在简体中文窗口的默认区域设置中,它指的是GBK。
1.2. MBCS
后来有人开始觉得代码太多让世界太复杂,让人头疼,于是大家坐在一起拍着脑袋想出一个方法:所有语言的字符都用同一个字符集表示,就是Unicode。
最初的Unicode标准UCS-2是用两个字节来表示一个字符,所以经常可以听到Unicode用两个字节来表示一个字符的说法。但是过了一段时间,有人觉得256*256太少或者不够用,于是出现了UCS-4标准,用4个字节代表一个字符,但是UCS-2还是我们用的最多的。
UCS(Unicode字符集)只是字符对应码位的列表。比如‘韩’的码位就是6C49。如何传输和存储字符是UTF(UCS转换格式)的责任。
起初,这很简单。直接用UCS的码位就是UTF-16。比如‘韩’直接用\x6C\x49保存(UTF-16-BE)或者反之。但是美国人在使用的时候觉得吃了大亏。以前英文字母只需要一个字节就可以保存。现在吃大锅饭就变成两个字节了,空间消耗翻倍.于是UTF-8诞生了。
UTF-8是一种笨拙的编码,具体表现为长度可变,兼容ASCII,ASCII字符用1个字节表示。但是,这里保存的东西一定是从其他地方挖出来的,你一定听说过ut。
F-8里中文字符使用3个字节来保存吧?4个字节保存的字符更是在泪奔……(具体UCS-2是怎么变成UTF-8的请自行搜索)
另外值得一提的是BOM(Byte Order Mark)。我们在储存文件时,文件使用的编码并没有保存,打开时则需要我们记住原先保存时使用的编码并使用这个编码打开,这样一来就产生了许多麻烦。(你可能想说记事本打开文件时并没有让选编码?不妨先打开记事本再使用文件 -> 打开看看)而UTF则引入了BOM来表示自身编码,如果一开始读入的几个字节是其中之一,则代表接下来要读取的文字使用的编码是相应的编码:
BOM_UTF8 '\xef\xbb\xbf'
BOM_UTF16_LE '\xff\xfe'
BOM_UTF16_BE '\xfe\xff'
并不是所有的编辑器都会写入BOM,但即使没有BOM,Unicode还是可以读取的,只是像MBCS的编码一样,需要另行指定具体的编码,否则解码将会失败。
你可能听说过UTF-8不需要BOM,这种说法是不对的,只是绝大多数编辑器在没有BOM时都是以UTF-8作为默认编码读取。即使是保存时默认使用ANSI(MBCS)的记事本,在读取文件时也是先使用UTF-8测试编码,如果可以成功解码,则使用UTF-8解码。记事本这个别扭的做法造成了一个BUG:如果你新建文本文件并输入"姹塧"然后使用ANSI(MBCS)保存,再打开就会变成"汉a",你不妨试试 :)
2. Python2.x中的编码问题
2.1. str和unicode
str和unicode都是basestring的子类。严格意义上说,str其实是字节串,它是unicode经过编码后的字节组成的序列。对UTF-8编码的str'汉'使用len()函数时,结果是3,因为实际上,UTF-8编码的'汉' == '\xE6\xB1\x89'。
unicode才是真正意义上的字符串,对字节串str使用正确的字符编码进行解码后获得,并且len(u'汉') == 1。
再来看看encode()
和decode()
两个basestring的实例方法,理解了str和unicode的区别后,这两个方法就不会再混淆了:
# coding: UTF-8u = 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)
需要注意的是,虽然对str调用encode()
方法是错误的,但实际上Python不会抛出异常,而是返回另外一个相同内容但不同id的str;对unicode调用decode()方法也是这样。很不理解为什么不把encode()和decode()分别放在unicode和str中而是都放在basestring中,但既然已经这样了,我们就小心避免犯错吧。
2.2. 字符编码声明
源代码文件中,如果有用到非ASCII字符,则需要在文件头部进行字符编码的声明,如下:
#-*- coding: UTF-8 -*-
实际上Python只检查#、coding和编码字符串,其他的字符都是为了美观加上的。另外,Python中可用的字符编码有很多,并且还有许多别名,还不区分大小写,比如UTF-8可以写成u8。参见
另外需要注意的是声明的编码必须与文件实际保存时用的编码一致,否则很大几率会出现代码解析异常。现在的IDE一般会自动处理这种情况,改变声明后同时换成声明的编码保存,但文本编辑器控们需要小心 :)
2.3. 读写文件
内置的open()方法打开文件时,read()读取的是str,读取后需要使用正确的编码格式进行decode()。write()写入时,如果参数是unicode,则需要使用你希望写入的编码进行encode(),如果是其他编码格式的str,则需要先用该str的编码进行decode(),转成unicode后再使用写入的编码进行encode()。如果直接将unicode作为参数传入write()方法,Python将先使用源代码文件声明的字符编码进行编码然后写入。
# coding: UTF-8f = 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()
另外,模块codecs提供了一个open()方法,可以指定一个编码打开文件,使用这个方法打开的文件读取返回的将是unicode。写入时,如果参数是unicode,则使用open()时指定的编码进行编码后写入;如果是str,则先根据源代码文件声明的字符编码,解码成unicode后再进行前述操作。相对内置的open()来说,这个方法比较不容易在编码上出现问题。
# coding: GBKimport codecs
f = codecs.open(test.txt, encoding=UTF-8)
u = f.read()
f.close()
print type(u) # <type unicode>
f = codecs.open(test.txt, a, encoding=UTF-8)
# 写入unicode
f.write(u)
# 写入str,自动进行解码编码操作
# GBK编码的str
s = 汉
print repr(s) # \xba\xba
# 这里会先将GBK编码的str解码为unicode再编码为UTF-8写入
f.write(s)
f.close()
2.4. 与编码相关的方法
sys/locale模块中提供了一些获取当前环境下的默认编码的方法。
import sysimport locale
def p(f):
print %s.%s(): %s % (f.__module__, f.__name__, f())
# 返回当前系统所使用的默认字符编码
p(sys.getdefaultencoding)
# 返回用于转换Unicode文件名至系统文件名所使用的编码
p(sys.getfilesystemencoding)
# 获取默认的区域设置并返回元祖(语言, 编码)
p(locale.getdefaultlocale)
# 返回用户设定的文本数据编码
# 文档提到this function only returns a guess
p(locale.getpreferredencoding)
# \xba\xba是汉的GBK编码
# mbcs是不推荐使用的编码,这里仅作测试表明为什么不应该用
print r"\xba\xba.decode(mbcs):", repr(\xba\xba.decode(mbcs))
#在笔者的Windows上的结果(区域设置为中文(简体, 中国))
#sys.getdefaultencoding(): gbk
#sys.getfilesystemencoding(): mbcs
#locale.getdefaultlocale(): (zh_CN, cp936)
#locale.getpreferredencoding(): cp936
#\xba\xba.decode(mbcs): u\u6c49
3.建议
3.1.字符编码声明
使用字符编码声明,并且同一工程中的所有源代码文件使用相同的字符编码声明。
这点是一定要做到的。
3.2. 抛弃str,全部使用unicode。
按引号前先按一下u最初做起来确实很不习惯而且经常会忘记再跑回去补,但如果这么做可以减少90%的编码问题。如果编码困扰不严重,可以不参考此条。
3.3. 使用codecs.open()替代内置的open()。
如果编码困扰不严重,可以不参考此条。
3.4. 绝对需要避免使用的字符编码:MBCS/DBCS和UTF-16。
这里说的MBCS不是指GBK什么的都不能用,而是不要使用Python里名为'MBCS'的编码,除非程序完全不移植。
Python中编码'MBCS'与'DBCS'是同义词,指当前Windows环境中MBCS指代的编码。Linux的Python实现中没有这种编码,所以一旦移植到Linux一定会出现异常!另外,只要设定的Windows系统区域不同,MBCS指代的编码也是不一样的。
分别设定不同的区域运行2.4小节中的代码的结果:
#中文(简体, 中国)#sys.getdefaultencoding(): gbk
#sys.getfilesystemencoding(): mbcs
#locale.getdefaultlocale(): (zh_CN, cp936)
#locale.getpreferredencoding(): cp936
#\xba\xba.decode(mbcs): u\u6c49
#英语(美国)
#sys.getdefaultencoding(): UTF-8
#sys.getfilesystemencoding(): mbcs
#locale.getdefaultlocale(): (zh_CN, cp1252)
#locale.getpreferredencoding(): cp1252
#\xba\xba.decode(mbcs): u\xba\xba
#德语(德国)
#sys.getdefaultencoding(): gbk
#sys.getfilesystemencoding(): mbcs
#locale.getdefaultlocale(): (zh_CN, cp1252)
#locale.getpreferredencoding(): cp1252
#\xba\xba.decode(mbcs): u\xba\xba
#日语(日本)
#sys.getdefaultencoding(): gbk
#sys.getfilesystemencoding(): mbcs
#locale.getdefaultlocale(): (zh_CN, cp932)
#locale.getpreferredencoding(): cp932
#\xba\xba.decode(mbcs): u\uff7a\uff7a
可见,更改区域后,使用mbcs解码得到了不正确的结果,所以,当我们需要使用'GBK'时,应该直接写'GBK',不要写成'MBCS'。
UTF-16同理,虽然绝大多数操作系统中'UTF-16'是'UTF-16-LE'的同义词,但直接写'UTF-16-LE'只是多写3个字符而已,而万一某个操作系统中'UTF-16'变成了'UTF-16-BE'的同义词,就会有错误的结果。实际上,UTF-16用的相当少,但用到的时候还是需要注意。
到此这篇关于一篇文章彻底弄懂Python字符编码的文章就介绍到这了,更多相关ython字符编码内容请搜索盛行IT软件开发工作室以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT软件开发工作室!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。