Python: 字符编码基础及中文乱码
一、字符编码基础字符编码是计算机对字符的格式化,从而能够在计算机系统中存储与传输。
1.ASCII码
在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出 256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从 0000000到11111111。
上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。
2.非ASCII编码
英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。 于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使 用的编码体系,可以表示最多256个符号。
但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码 中代表了é,在希伯来语编码中却代表了字母Gimel(ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0—127表示的符号是一样的,不一样的只是128—255的这一段。
至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。 比如,简体中文常见的编码方式是GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示256x256=65536个符号。
3.Unicode
世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。
可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是Unicode,就像它的名字都表示的,这是一种所有符号的编码。Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母 Ain,U+0041表示英语的大写字母A,U+4E25表示汉字“严”。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表。
Unicode的问题
需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。比如,汉字“严”的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。这里就有两个严重的问题,第一个问题是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号 呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必 然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。它们造成的结果是:
1)出现了unicode的多种存储方式,即有许多种不同的二进制格式,可以用来表示unicode。
2)unicode在很长一段时间内无法推广,直到互联网的出现。
4.UTF-8
互联网的普及,强烈要求出现一种统一的编码方式。UTF-8就是在互联网上使用最广的一种unicode的实现方式。其他实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8是Unicode的实现方式之一。
UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。UTF-8的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。下表总结了编码规则,字母x表示可用编码的位。
http://p.blog.csdn.net/images/p_blog_csdn_net/kiki113/EntryImages/20090410/utf8.jpg
下面,还是以汉字“严”为例,演示如何实现UTF-8编码。
已知“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(00000800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx10xxxxxx”。然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是 “11100100 10111000 10100101”,转换成十六进制就是E4B8A5。
5.Windos下Unicode与UTF-8之间的转换
在Windows平台下,有一个最简单的转化方法,就是使用内置的记事本小程序Notepad.exe。打开文件后,点击“文件”菜单中的“另存为”命令,会跳出一个对话框,在最底部有一个“编码”的下拉条。
http://p.blog.csdn.net/images/p_blog_csdn_net/kiki113/EntryImages/20090410/SaveAs.jpg
里面有四个选项:ANSI,Unicode,Unicode big endian 和 UTF-8。
1)ANSI是默认的编码方式。对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。
2)Unicode编码指的是UCS-2编码方式,即直接用两个字节存入字符的Unicode码。这个选项用的little endian格式。
3)Unicode big endian编码与上一个选项相对应。我在下一节会解释little endian和big endian的涵义。
4)UTF-8编码,也就是上一节谈到的编码方法。
选择完”编码方式“后,点击”保存“按钮,文件的编码方式就立刻转换好了。
其中:Little endian和Big endian:
Unicode码可以采用UCS-2格式直接存储。以汉字”严“为例,Unicode码是4E25,需要用两个字节存储,一个字节 是4E,另一个字节是25。存储的时候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。
计算机怎么知道某一个文件到底采用哪一种方式编码?
Unicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做”零宽度非换行空格“(ZERO> --------------------------------------------------------------------------------------
二、python中的中文编码
1.python中的unicode、str和print
unicode,一般指unicode对象,例'哈哈'的unicode对象为u'/u54c8/u54c8'
str,是一个字节数组,这个字节数组表示的是对unicode对象(可以是utf-8、gbk、cp936、GB2312)编码后的存储的格式。这里它仅仅是一个字节流,没有其它的含义,如果你想使这个字节流显示的内容有意义,就必须用正确的编码格式来解码显示
print,语句print的的实现是将要输出的内容传送给操作系统,操作系统会根据系统的编码对输入的字节流进行编码
2.unicode、str和print之间的转换
我们以中文“哈哈”为例,“哈哈”的编码如下:
<1>定义一个字符串变量test = '哈哈',并查看在计算机中的存储:
http://blog.51cto.com/5319188/data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIgAAABhCAIAAACCk35PAAADVklEQVR4nO2bQZbjIAxEfbQcLUfz0WbRb/wcEEKFQSk79Vc0EZKgTGNC2N7v9+v12gQbEuYi+74vsZcwF5Ew32Q/UdRv1lij9gYSJsIxlOcxLcrmR0F7g0OYlila/wBaT7pZKFoVcyJob8Q9z5jV2swScvUD4Qvj9NrUI2JvxC3+la3TZtYMS5ipwRlTM2xvxK3XmBXa+H0wE+0aR+IONGkNWVHoOoHsjbjm4r9OG6cyUg7Gmk6ta6136wGK2BvkzJiWWbdvw+EiISAnrUJtM2Bv8N01ptu8Nhge3CtEhtUUBqr5IO2t7DA+t0LLLT/5oAM9LsxSVc5NzBkQr2/5SSZPGAGxW0y0lzCDaMb8KhKGFAlDioQhRcKQovMYUnQeQ4rOY0h5/HnMXdF5DCmPP4+5KzqPIUXnMaToPIYU7fxJkTCkSBhSJAwpEoYUCUOKhCElssGM4+wwnH3JxCjrPGfn3xVmbBfpVBYGw/6DY3TX/CPCQLEHOnbd/2r7L+Tf/UrG/MhJbv+kZXDRfyvJ7rDeJv/g4u/EDiZhdhj133LS7fn98o+/lbVitxLy053iv7ZsDdz98odelwunczs24D/o9pb5o/uYw0VdqGM4H03xHwl61/wHNpj7f7rZ1DbdjkX8O32Ljx17/tr5kyJhSJEwpEgYUiQMKRKGFAlDCvn9mJwojGTejxkACoEmMyv5JYOQ9tvl1aCZzMp81Qhk3o/Zqq8rzn8WfsqvKKpKpz6YT9dVq8lwXICv3I8xy85wdJ0Ec+jm3E3yetwoX7kfU5d3a9LUNTnCnOn6TxJmkSpb+AH0/ecIA7XKEGadKluiMMGsTHu0PBA3Sto+Zv+krvTt/UEsmqApteJG6gfihkjb+c9P/dnkCOM8bsJG35WR0hUGfcY1J+YgYUj5E8Z5FdmssUbtBcwhzN+f++cb+rlsfhS0FzAtYfy3ddRewNTCOKNp6hGxFzDOjKk5WqH2AsZZYxxQewHTeivrzhjIXsBAi39dDtoLmEKYg6AwUI0AaO380YGWMJORMKQ4wkCLuRb/yWjGkKLzGFIkDCkShhQJQ4qEIYX8fszvQn4/5nd5zP2Yp5H2a3+BkXY/RmBoxpCiNYYUvZWRon0MKdr5kyJhSJEwnPwDCo8NdbHePesAAAAASUVORK5CYII=
我们已经看到,'哈哈'在计算机中按照某种编码方式存储了下来,而在print的时候,print函数对存储的test进行了默认编码输出。
<2>将test进行str操作:
http://blog.51cto.com/5319188/data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMEAAABnCAIAAAA2ZbE4AAADrElEQVR4nO2ZWZaEIAxF3f+qWFp/tccCMjEoyr1fdowvMbyyCvs4fkkpmZGefAAAAAAAAMhIKVV3UtE43MzNC2GUm22jUbe6ms4oGvqpLsHs+Txmo1Efl9V0RtHQj2SgG+bzgI1SQfWUdIlHx1Pa1Ln+2aAfHUVPP9VaSjNSh6F+yguN++yPmznlvPRjZy1TX9E548r4mhnYT2gtZsxZSwg15ymmpKWCUeWada6deGoptzC1n5DOjDmLCW13qFTSMxsa9Vds02nTf6Qf/0iHz/kBA12Tr1dFjyUds6hfZ6qHhvejrP28OYstSSeicYX0TzXojEs6ZlGPjpI8iuH9KKPz1I3OeepwniQJPN0XAAAAAAAAwI1Im+FoHLZmto1GeW41Hfhhno1GPbdW04EKM2ykvEGWXiubyU4ThHSuf2KyLubZSAl6jp21TH1FJ/MQNmphhoGkNOl50F+uWefaCR5qYZKBpEzz8jKhbV39Ovimi3kGOorviFLBcyzpmEX9OnionakGul5SfR7445KOWdSjoyTDx0kCT/cFAAAAAAAAcC/9+2FlUz1wyz1v675m/296TyG9iBsikuT3xW36zsm+vf9Q5vOY4xsiUq5Bv/7s/Af7b7vkGZRGy1PKHNMvUkKnvtSk6YDX9S/lvw/l3pzzqq5NVF8SMRfp7f1/BGlM0uyUS0bpl5nSGn+g/4+Q3d7YNWjQd8p+pv+PcN5teZAl6KeG6HuKfqz/j5D+ySLlQZnjmY6pryyDf5nf2z8AAAAAAAAAwBykNxPR+Fh4X/IyFrRRqES0mVHNr6bzMAvayEm0k1Gdr6azBDNsVL7sv8bT7/8ZslNSUIk7+zGlpEua60Z1rn869VdBajcal3Kqx8rKmSLOHsyezSY76zbo6PNZlBkGOqwlScJH7REPXTH1h9Q149J8VmSSgQ73x1rXv8dDoava1tWv8w7fnMwz0HGjh5xdVfOjx9G6DTpv8tBUA535J2VQz9fXO7sk2pJU1xOP1g3pKMk7stUgyg/AVrc/BeYIAB1Enxw8aSAHD4EXaTNy1GyhbF6q+bAR2cbyelw95cyHjaia44yczijT9HzYCH3hq9bx5MNGlOao/vRRzCT9VIJdcC688hUG+5I9PMznUCgfNkJ5wJjfZUo+7IjTQ6EI7EXUE3gIcvAQ9BL9jcxvasjhOQQAAAAAAHAz0m48GoetwUYwAGwEA8BGMABsBF1gIOgCA0EXGAi6wEAAAAAAAAAAAADQwR8OcoMEBkgASgAAAABJRU5ErkJggg==
与<1>相同,可见str只是对test编码后的一个存储格式。
<3>将test进行gbk编码
http://blog.51cto.com/5319188/data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQ0AAABjCAIAAAAO+cLBAAAEuklEQVR4nO3dS2KbMBCAYY7mo+VoWnbZRQ+URVsH6zEPoSf834pgoRmExgQTh+PP719fX1+v1+sAUEKdADrqBNBRJ4COOgF05zoJIYQQ0jbe9VsI/xnX30bvHazoP21v76HuOAqb5MNE55PepdLq8DTpZ2L9zx2H3jvo6t89Zc3hvHUibZL+3tWvVFodnt79LDWNevSzzg42OQQN66T4Uvb6pEephET2pdImln7U0FGqcj5Nds3VeNg4XIlrXG/vv5SnkP9x7Tiqw5VpULqOr9sHIXapjWVnhP1XGfvJLrsC2S01DrOWW+VvCec9jpn2w84npWYh0Spc2tg1vvYowi6oKVk66ToOpbiWoPZl13658jeGNkYpJjb9+kTdPG0wZny9geyWGocrh9u7bI9ij2sJXT1QP0Z+3pXNu2KsvfsfPmWTN4ZuYsA4XN/Z3svZxGThU/WuqSEyLwy+f5Lu5PG5/5b1pX6M0aPlqKvsj64o9kz6jYPcz5Ebiuv5ePuPNsy+pLaPIqZB7SGkNre5Hx9E5zYzs0StycfxNnUiUN/PsIWZx/EJdQJcRZ0AOuoE0FEngI46AXR8/8S4Ho/G90/s6/Fc0/++q0LvfqgTxPj+SSmEfddwf3z/RFimSPAP3z8pLVMk+DH9+kTdPG0wpk68gXBnfP/EFRoPxfdPoq6yP7qi4IZucz8+iM5tZmaJTd2mTgTCeQkweUKdAFdRJ4COOgF01Amgo04AnbFOrn9YVPqstiJKk8+vxuTDh2w3caVOXDNAnTHGqS/cD1ktH0sU7OFindgngdzYfoqQ62SpfLwpYV3vOqmbf/LMkOdQukk2bmmlGn16PhTJfVjqRCZMjnS5NM/sy0dhvi6bD+7gep0c/vdsYb6+X1K3NZbKCvlge03q5Eimi9yPd3572yyYD/bWqk6Oz3fitJ8rc87bz5r5YGPp90+C+GuG7Lxt2k86caNts9M6bS/3s3I+2BX34wEddQLoqBNAR50AOuoE0FEngI46AXTrP//kIfclSndguDOzhMHPP6ngCuFNplXyTfqZ+34Eycj/L9ybN5NWmffuZ50Rfq7Bzz85kl8kzj9G/YST7EphvTEftavSJtVxhV2W80mXMc6s559kl4XZqXZizEHNWU3yYlxjP8L4GAOhpVnPP0mXS1NhSp2cqf2PqROKZKZZzz8Rpovc/5g6cW01pk68gdDSlOefCMtqCMs8M2aVbe9dro77pu6afazQy8j7J9n5kZ0x2fbynI428aZUimtZXxH3vFW0XBqfdBOMM/J+/KOOcVrkaZk9akD2NqxOhDfjp2Eo9sPfdwE6S51U/Np9ISNgPdQJoIv+L1H6S/P7Q5hoQ297YGPnOvm75jzFo+XsS8b2wMaEOhHOIdlmcntgY9k6ESZ3tjws7YGNyeeT1HtDb3tgY/L1icDbHtiY8HmXej5xtQc25r2OT5eN7YGNpXXyZqwT1xpgS8L9eO+8p05wW9QJoJPrxHVdznU8bovzCaDj+yeAjjoBdNQJoKNOAB11AujWf/4JMN/6zz8B5rvT80+AXkb+v3pgVyOffwLsivMJoOP6BNDxeReg4/4JoON+PKCjTgAddQLoqBNAR50Aqm9aXNDEVPY7zwAAAABJRU5ErkJggg==
test的存储形式发生了变化,这是因为不同编码方式造成的
<4>将test进行utf-8编码
http://blog.51cto.com/5319188/data:image/png;base64,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
这时发生了错误,于是我们进行了以下测试:
http://blog.51cto.com/5319188/data:image/png;base64,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 http://blog.51cto.com/5319188/data:image/png;base64,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
由此看到,
(1)我们无法直接对test进行utf-8的编码,而需要经过对其特定编码之后才可以完成utf-8的编码,这是因为在python中str和unicode在编码和解码过程中,如果将一个str直接编码成另一种编码,会先把str解码成unicode,采用的编码为默认编码,一般默认编码是anscii,所以在上面示例代码中第一次转换的时候会出错,当设定当前默认编码为'gbk'后,就不会出错了。当然,我们也可以把这个默认编码给改了,如下:
http://blog.51cto.com/5319188/data:image/png;base64,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
(2)由于在对test进行utf-8编码之后,print语句将要输出的内容('/xe5/x93/x88/xe5 /x93/x88')传送了操作系统,操作系统会根据系统的编码对输入的字节流进行编码,从而输出的是“鍝堝搱”(注:'/xe5/x93/x88/xe5 /x93/x88'用GB2312去解释,其显示的出来就是“鍝堝搱”,)
(3)以上所有例子中print函数所输出的'哈哈'(gbk编码)与'鍝堝搱'(GB2312),而gbk是GB2312的扩展,前者兼容后者,可见,print默认编码应该是gbk了。
(4)test = u'哈哈'是定义了一个unicode类型的变量,所以可以直接encode,decode就是把其他编码转换为unicode,encode就是把unicode编码的字符串转换为特定编码,这也是例子中直接从对str类型的test进行encode发生错误的原因。
3.python文件的编码格式和编码声明的作用
(1)文件的编码格式决定了在该源文件中声明的字符串的编码格式,例如:
str = '哈哈',print repr(str)
a.如果文件格式为utf-8,则str的值为:'/xe5/x93/x88/xe5/x93/x88'(哈哈的utf-8编码)
b.如果文件格式为ANSCII,则str的值为:'/xb9/xfe/xb9/xfe'(哈哈的ANSCII编码)
而在python中的字符串,只是一个字节数组,所以当把a情况的str输出到 gbk编码的控制台时,就将显示为乱码:鍝堝搱;而当把b情况下的str输出utf-8编码的控制台时,就会报错。
(2)在py程序的开头会用#coding=gbk 类似的语句声明一下编码,这句话作用是:
a.声明源文件中将出现非ascii编码(通常也就是中文);
b.在高级的IDE中,IDE会将你的文件格式保存成你指定编码格式。
c.决定源码中类似于u'哈哈'这类声明的将‘哈哈’解码成unicode所用的编码格式,例如:
#coding:gbk
ss = u'哈哈'
print repr(ss)
print 'ss:%s' % ss
将这个些代码保存成一个utf-8文本,运行,你认为会输出什么呢?大家第一感觉肯定输出的肯定是:
u'/u54c8/u54c8'
ss:哈哈
但是实际上输出是:
u'/u935d/u581d/u6431'
ss:鍝堝搱
为什么会这样,这时候,就是编码声明在作怪了,在运行ss = u'哈哈'的时候,整个过程可以分为以下几步:
1) 获取'哈哈'的编码:由文件编码格式确定,为'/xe5/x93/x88/xe5/x93/x88'(哈哈的utf-8编码形式)
2) 转成 unicode编码的时候,在这个转换的过程中,对于'/xe5/x93/x88/xe5/x93/x88'的解码,不是用utf-8解码,而是用声明编码处指定的编码GBK,将'/xe5/x93/x88/xe5/x93/x88'按GBK解码,得到就是''鍝堝搱'',这三个字的unicode编码就 是u'/u935d/u581d/u6431',至止可以解释为什么print repr(ss)输出的是u'/u935d/u581d/u6431' 了。
总结:
1.任何字符在内存中都是以一种编码形式存储,而不是存储它本身,我们只可能在存入内存之前或者在从内存中拿出来之后,适当的进行编码与解码,即可得到我们想要的结果。
2.打印列表,打印的是所有元素在内存中的形式,而逐个打印列表的元素的时候,print将其传送给操作系统进行了默认编码,我们看到的是结果。
页:
[1]