开元棋牌网站怎么做,短网址生成短链接,做效果图的网站有哪些,中小学校网站建设Python字符编码详解 http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html本文简单介绍了各种常用的字符编码的特点#xff0c;并介绍了在python2.x中如何与编码问题作战 #xff1a;#xff09; 请注意本文关于Python的内容仅适用于2.x#xff0c;3.x中str和…Python字符编码详解 http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html 本文简单介绍了各种常用的字符编码的特点并介绍了在python2.x中如何与编码问题作战 请注意本文关于Python的内容仅适用于2.x3.x中str和unicode有翻天覆地的变化请查阅其他相关文档。 尊重作者的劳动转载请注明作者及原文地址 . 1. 字符编码简介 1.1. ASCII ASCII(American Standard Code for Information Interchange)是一种单字节的编码。计算机世界里一开始只有英文而单字节可以表示256个不同的字符可以表示所有的英文字符和许多的控制符号。不过ASCII只用到了其中的一半\x80以下这也是MBCS得以实现的基础。 1.2. MBCS 然而计算机世界里很快就有了其他语言单字节的ASCII已无法满足需求。后来每个语言就制定了一套自己的编码由于单字节能表示的字符太少而且同时也需要与ASCII编码保持兼容所以这些编码纷纷使用了多字节来表示字符如GBxxx、BIGxxx等等他们的规则是如果第一个字节是\x80以下则仍然表示ASCII字符而如果是\x80以上则跟下一个字节一起共两个字节表示一个字符然后跳过下一个字节继续往下判断。 这里IBM发明了一个叫Code Page的概念将这些编码都收入囊中并分配页码GBK是第936页也就是CP936。所以也可以使用CP936表示GBK。 MBCS(Multi-Byte Character Set)是这些编码的统称。目前为止大家都是用了双字节所以有时候也叫做DBCS(Double-Byte Character Set)。必须明确的是MBCS并不是某一种特定的编码Windows里根据你设定的区域不同MBCS指代不同的编码而Linux里无法使用MBCS作为编码。在Windows中你看不到MBCS这几个字符因为微软为了更加洋气使用了ANSI来吓唬人记事本的另存为对话框里编码ANSI就是MBCS。同时在简体中文Windows默认的区域设定里指代GBK。 1.3. Unicode 后来有人开始觉得太多编码导致世界变得过于复杂了让人脑袋疼于是大家坐在一起拍脑袋想出来一个方法所有语言的字符都用同一种字符集来表示这就是Unicode。 最初的Unicode标准UCS-2使用两个字节表示一个字符所以你常常可以听到Unicode使用两个字节表示一个字符的说法。但过了不久有人觉得256*256太少了还是不够用于是出现了UCS-4标准它使用4个字节表示一个字符不过我们用的最多的仍然是UCS-2。 UCS(Unicode Character Set)还仅仅是字符对应码位的一张表而已比如汉这个字的码位是6C49。字符具体如何传输和储存则是由UTF(UCS Transformation Format)来负责。 一开始这事很简单直接使用UCS的码位来保存这就是UTF-16比如汉直接使用\x6C\x49保存(UTF-16-BE)或是倒过来使用\x49\x6C保存(UTF-16-LE)。但用着用着美国人觉得自己吃了大亏以前英文字母只需要一个字节就能保存了现在大锅饭一吃变成了两个字节空间消耗大了一倍……于是UTF-8横空出世。 UTF-8是一种很别扭的编码具体表现在他是变长的并且兼容ASCIIASCII字符使用1字节表示。然而这里省了的必定是从别的地方抠出来的你肯定也听说过UTF-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但即使没有BOMUnicode还是可以读取的只是像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的区别后这两个方法就不会再混淆了 ? 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) # \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字符则需要在文件头部进行字符编码的声明如下 ? 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将先使用源代码文件声明的字符编码进行编码然后写入。 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 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() 另外模块codecs提供了一个open()方法可以指定一个编码打开文件使用这个方法打开的文件读取返回的将是unicode。写入时如果参数是unicode则使用open()时指定的编码进行编码后写入如果是str则先根据源代码文件声明的字符编码解码成unicode后再进行前述操作。相对内置的open()来说这个方法比较不容易在编码上出现问题。 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # coding: GBK import codecs f codecs.open(test.txt, encodingUTF-8) u f.read() f.close() print type(u) # type unicode f codecs.open(test.txt, a, encodingUTF-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模块中提供了一些获取当前环境下的默认编码的方法。 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # coding:gbk import sys import 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小节中的代码的结果 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #中文(简体, 中国) #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用的相当少但用到的时候还是需要注意。 转载于:https://www.cnblogs.com/kungfupanda/p/4318743.html