编码与解码(python 经验)

来源:互联网 发布:淘宝能贷款的口子 编辑:程序博客网 时间:2024/05/17 23:53

编码与解码(python 经验)

关键词:编码; ASCII; ANSI; Unicode; utf-8; 字节序和BOM; MIME(待续)

背景知识

Bit:

比特(Bit),也称二进制位,指二进制中的一位,是计算机信息的最小单位。Bit是Binary digit(二进制数位)的缩写,还可被缩写为b。

字节(港澳台称位元组,Byte),一个字节代表8个比特,也被缩写为B,在工业标准、网络、电信技术中也被成为八位组(Octet)。
字面量,可以理解为给人看的内容,比如在python代码中有:

str_demostr_demo = "abc"str_demo_1 = "中国"

abc 和 中国 就是字面量,而字面量的值即默认工作字符集的编码。

编码的演进故事

编码:

编码即转换,字符编码(character encoding),是把字符集中的字符编码为指定集合中的某一对象(比特、自然数序列、电脉冲),以便文本在计算机中存储和通过网络传递。比如:将拉丁字母表编码成ASCII。而ASCII将字母、数字和其它符号编号,并用7比特的二进制来表示这个整数,通常会额外使用一个扩充的比特,比便于以一个字节的方式存储。

内码 & ASCII & ANSI:

字符内码(character code)指的是用来代表(编码)字符(字面量)的计算机内码,程序在输入和存储文档时都要使用内码,内码分为:单字节内码,可以支持256个字符编码,双子节内码可以支持65000个字符编码,前者为ASCII,后者对应ANSI。

ASCII(发音:/ˈæski/)

American Standard Code for Information Interchange,美国信息交换标准代码,是基于拉丁字母的一套编码系统。它主要用于现实现代英语,至今为止(1986年)共定义了128个字符;其中95个可显示字符(空格也算)其它33个字符是图案或多已废弃的控制符。

而我们博大精深的中文(还有很多其它亚洲文字),文字N多,所以使用了双字节的方式,GB2312(简体中文编码的一种),实际上是ANSI的一个代码页(936),使用不同代码页的内码无法在其它代码页正常显示,中英混排字数统计等问题仅仅使用扩展ASCII是比较痛苦的。

那么能不能用一种编码集应对所用文字呢?于是乎伟大的Unicode诞生了

Unicode:

也被称为国际码,统一码,它对大部分文字进行了整理编码,它伴随着通用字符集(Universal Character Set, UCS)的标准而发展,到2016年6月21日公布的9.0.0版本,已经收入了10万+个字符。

然而这个世界不是理想的,不可能一夜之间所有系统都使用Unicode来处理字符,所以在Unicode诞生之日就面临一个严峻的考验:兼容!

UTF-8:

所有字符的Unicode编码是确定的,但是在传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式(Unicode Transformation Format)

utf-8可以说是让Unicode能够真正落地实施的方案,它以8位为单元对Unicode进行变长编码。它将基本7位ASCII字符仍用7位编码表示,占用一个字节(首位补0)。而遇到与其他Unicode字符混合的情况,将按一定算法转换,每个字符使用1-3个字节编码,并利用首位为0或1进行识别。

从Unicode到UTF-8的编码转换方式如下:

     Unicode编码(16进制)     UTF-8 字节流(二进制)

     0000 - 007F         0xxxxxxx

     0080 - 07FF         110xxxxx 10xxxxxx

     0800 - FFFF         1110xxxx 10xxxxxx 10xxxxxx

此外Unicode的实现方式还有UTF-7、UTF-16、UTF-32、Punycode、CESU-8、SCSU、GB18030等,这些实现方式有些仅在一定的国家和地区使用,有些则属于未来的规划方式。

目前通用的实现方式是UTF-16小端序(LE, Little Endian)、UTF-16大端序(BE, Big Endian)和UTF-8。
字节序和BOM

双字节编码一个字符的时候,就会遇到字节序的问题,比如:“中”的Unicode编码是4e 2d,大数在前就是大端。

BOM(Byte Order Mark)

主要目的是表明编码字节序,实现上是一个有点小聪明的想法:

在UCS编码中有一个叫做”ZERO WIDTH NO-BREAK SPACE”的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符”ZERO WIDTH NO-BREAK SPACE”。

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符”ZERO WIDTH NO-BREAK SPACE”又被称作BOM。

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符”ZERO WIDTH NO-BREAK SPACE”的UTF-8编码是EF BB

Python编码问题Tip

1、Unicode做为中间码传输,显示的时候再根据需要转码

2、Python中有个包叫chardet,它是用来猜测编码的,注意是猜测

3、如果一个字符串的字面量保存成了编码,想要变回真正的字面量时,通用的做法需要用正则搞一下,然而往往情况比较简单,只需要decode(string_escape),比如下面这个字符串的内容:

>>> abc = "\\xe4\\xb8\\xadabc\\xe5\\x9b\\xbd123">>> print abc\xe4\xb8\xadabc\xe5\x9b\xbd123>>> print abc.decode('string_escape')中abc国123
0 0