字符集编码与Python(一)编码历史

相信有很多人和我一样,在写代码的时候经常会被一些各种字符集编码的问题困扰吧,于是最近心血来潮准备好好的嚼嚼字符集编码 要好好的了解字符集编码,我们肯定从各种编码集的历史说起了,下面本篇就主要着手于介绍字符集编码的历史


#编码历史

##ASCII

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。ASCII 是一种字符编码,同时也是一种最简单的字符集编码,把128 个字符映射至整数0 ~ 127。

在 ASCII码里面,虽然你看到的是一个字符,但是对于计算机来说,存的就是二进制的整数,也就是说你看到的可能是abcd,但是计算机内部存的就是97 98 99 100。

ASCII这种7-bit 字符编码系统非常简单,在计算机中以一个字节存储一个字符。如下所示,

我安装了一个ascii 下面就是详细的信息:

[root@iZ28b4rx8dxZ ~]# yum install ascii
[root@iZ28b4rx8dxZ ~]# ascii
Usage: ascii [-dxohv] [-t] [char-alias...]
   -t = one-line output  -d = Decimal table  -o = octal table  -x = hex table
   -h = This help screen -v = version information
Prints all aliases of an ASCII character. Args may be chars, C \-escapes,
English names, ^-escapes, ASCII mnemonics, or numerics in decimal/octal/hex.
 
Dec Hex    Dec Hex    Dec Hex  Dec Hex  Dec Hex  Dec Hex   Dec Hex   Dec Hex 
  0 00 NUL  16 10 DLE  32 20    48 30 0  64 40 @  80 50 P   96 60 `  112 70 p
  1 01 SOH  17 11 DC1  33 21 !  49 31 1  65 41 A  81 51 Q   97 61 a  113 71 q
  2 02 STX  18 12 DC2  34 22 "  50 32 2  66 42 B  82 52 R   98 62 b  114 72 r
  3 03 ETX  19 13 DC3  35 23 #  51 33 3  67 43 C  83 53 S   99 63 c  115 73 s
  4 04 EOT  20 14 DC4  36 24 $  52 34 4  68 44 D  84 54 T  100 64 d  116 74 t
  5 05 ENQ  21 15 NAK  37 25 %  53 35 5  69 45 E  85 55 U  101 65 e  117 75 u
  6 06 ACK  22 16 SYN  38 26 &  54 36 6  70 46 F  86 56 V  102 66 f  118 76 v
  7 07 BEL  23 17 ETB  39 27 '  55 37 7  71 47 G  87 57 W  103 67 g  119 77 w
  8 08 BS   24 18 CAN  40 28 (  56 38 8  72 48 H  88 58 X  104 68 h  120 78 x
  9 09 HT   25 19 EM   41 29 )  57 39 9  73 49 I  89 59 Y  105 69 i  121 79 y
 10 0A LF   26 1A SUB  42 2A *  58 3A :  74 4A J  90 5A Z  106 6A j  122 7A z
 11 0B VT   27 1B ESC  43 2B +  59 3B ;  75 4B K  91 5B [  107 6B k  123 7B {
 12 0C FF   28 1C FS   44 2C ,  60 3C <  76 4C L  92 5C \  108 6C l  124 7C |
 13 0D CR   29 1D GS   45 2D -  61 3D =  77 4D M  93 5D ]  109 6D m  125 7D }
 14 0E SO   30 1E RS   46 2E .  62 3E >  78 4E N  94 5E ^  110 6E n  126 7E ~
 15 0F SI   31 1F US   47 2F /  63 3F ?  79 4F O  95 5F _  111 6F o  127 7F DEL
[root@iZ28b4rx8dxZ ~]#

 

##Latin-1

虽然ASCII好用,但是,很多时候一个字符用一个字节并不够。例如,各种符号和重音字符并不在ASCII所定义的可能字符的范围中,

为了容纳特殊字符,一些标准允许一个8位字节的所有bit都用来表示字符,那么,一个字节最多就可以表示255个字符了,这样的一个标准叫 latin-1

Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。

因为Latin-1 编码范围使用了单字节内的所有空间,在支持Latin-1 的系统中传输和存储其他任何编码的字节流都不会被抛弃。换句话说就是把其他任何编码的字节流当作Latin-1 编码看待都没有问题。这是个很重要的特性,MySQL数据库默认编码是Latin1就是利用了这个特性

在latin-1中,127以上的字符代码分配给了重音和其他特殊字符

    >>> print chr(169)
    ©
    >>> print chr(189)        #chr这个函数把数字转换成字符
    ½
    >>> print chr(174)
    ®

 

###总结 latin-1ASCII 的区别:

 

##GB 2312

GB 2312是一个简体中文汉字编码国家标准,GB2312对汉字采用双字节编码,由6763个常用汉字和682个全角的非汉字字符组成。其中汉字根据使用的频率分为两级。一级汉字3755个,二级汉字3008个。由于字符数量比较大,GB2312采用了二维矩阵编码法对所有字符进行编码。

 

##BIG5编码

台湾地区繁体中文标准字符集,采用双字节编码,也称为大五码,具体的信息我就不介绍了,百度上一堆

 

##GBK编码

1995年12月发布的汉字编码国家标准,是对GB2312编码的扩充,对汉字采用双字节编码。GBK字符集共收录21003个汉字,包含国家标准GB13000-1中的全部中日韩汉字,和BIG5编码中的所有汉字。

最一开始,在Unicode 出现之前,各地区国家制定了不同的编码系统,也就是说中文自己进行编码,如GB 2312 和大五码等,日文也自己进行编码,如主要用JIS ,这样会造成混乱不便,例如一个文本信息里面混合了不同的语言,就不能正确的表示信息,也就是无法进行混合的使用。

 

##Unicode

Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字,以满足跨语言、跨平台进行文本转换、处理的要求。

统一码为每一个字符而非字形定义唯一的代码(即一个整数)。换句话说,统一码以一种抽象的方式(即数字)来处理字符,并将视觉上的演绎工作(例如字体大小、外观形状、字体形态、文体等)留给其他软件来处理,例如网页浏览器或是文字处理器

Unicode是为了解决传统的字符编码方案的局限而产生的

每个字符映射至一个整数码点(code point),码点的范围是0 至0x10FFFF,在表示一个Unicode的字符时,通常会用 U+ 然后紧接着一组十六进制的数字来表示这一个字符。在Python中,用 \uxxxx 表示。所以有的时候用写Python的过程中看到了像 \u 四个十六进制的的字符的话,说明这个字符是Unicode。

其中Unicode 还制定了各种储存码点的方式,这些方式称为Unicode 转换格式(Uniform Transformation Format, UTF)。

现在流行的UTF 为 UTF-8UTF-16UTF-32 。每种UTF 会把一个码点储存为一至多个编码单元(code unit)。例如UTF-8 的编码单元是8 位的字节、UTF-16 为16 位、UTF-32 为32 位。除UTF-32 外,UTF-8 和UTF-16 都是可变长度编码。

其中UTF-8 成为现在互联网上最流行的格式,有几个原因:

单字节的情况下不会出现大端小端的问题,比如说有两个字节,ab就要考虑是a放在前面还是b放在前面,对于大端的话就是a放前面,对于小端的话就是b放前面。我们常用的X86结构是小端模式

 

##UTF-8的实现

首先声明:utf8Unicode 并不是竞争的关系

UTF-8 的编码单元是8 位字节,每个码点编码成1 至4 个字节。它的编码方式很简单,按照码点的范围,把码点的二进位分拆成1 至最多4 个字节

UTF-8 编码方法的好处之一是,码点范围U+0000 ~ U+007F 编码为一个字节,与ASCII 编码兼容。这范围的 Unicode 码点也是和ASCII 字符相同的。因此,一个 ASCII 文本也是一个 UTF-8 文本

也就是说Unicode编码成utf-8有自己的一套编码方法

码点范围码点位数字节1字节2字节3字节4
U+0000 ~ U+007F70xxxxxxx   
U+0080 ~ U+07FF11110xxxxx10xxxxxx  
U+0800 ~ U+FFFF161110xxxx10xxxxxx10xxxxxx 
U+10000 ~ U+10FFFF2111110xxx10xxxxxx10xxxxxx 

用Python举个例子解释一下:

    In [24]: name = u'张三'
     
    In [25]: name
    Out[25]: u'\u5f20\u4e09'

把“张三”编码成为 `utf-8`

    In [26]: name.encode('utf-8')
    Out[26]: '\xe5\xbc\xa0\xe4\xb8\x89'     #张:e5 bc a0  三:e4 b8 89 

这其中的转换过程如下所示:

把5f20和4e09分别翻译成二进制然后转为 utf-8


5f20:

翻译为二进制:

0101      1111      0010      0000

按照上面码点范围的转换方式,5f20 应该属于第三个范围 也就是

1110+0101(四位)+10+111100(六位)+10+100000(六位):

1110 0101 1011 1100 1010 0000

    e         5       b        c         a       0


4e09:

翻译为二进制:

0100    1110    0000    1001

按照上面码点范围的转换方式,4e09 应该属于第三个范围 也就是

1110+0100(四位)+ 10 +111000(六位)+ 10 +001001(六位):

1110 0100 1011 1000 1000 1001

    e         4       b         8         8       9

下一篇详细理解Python里面Unicodeutf-8


Hello, I am Mingyue Li. Read my thoughts on IT and Life

Copyright Declaration:

All articles and pictures contained on this web site is copyright protected. If reproduced, must contain this statement, and indicate the original author and the original address of this article