字符那些事
一、编码是什么
编码为了某种目的把信息从一种形式集合转换为另一种形式集合的过程,古时的鸣金收兵,从某种意义上讲也是一种编码,将帅发出了退兵的命令,为了让更多的人能够知道这个命令,传令兵把这个信息转换为了锣声,传递了出去
与编码相对的还有解码,解码是根据某种规则将信息恢复到原状的过程,士兵之前都接收过训练,在听到锣声之后,明白到锣声代表退兵,便开始执行这一命令。
旗语,电报中的莫斯电码等等,这些东西里面也包含了编码
二、关于字符集和字符编码
因为计算机中的信息都是用二进制数表示的,所以我们必须将汉字、英文按照一定的规则表示出来储存在计算机中
所以字符编码就是为了信息处理,将自然语言中的一个集合与另一个集合如(如号码和电脉冲)进行配对,建立对应关系,常见的编码方式有ASCII,GBK,GB2312,utf8,utf16,utf32等
字符集就是是一个系统支持的所有抽象字符的集合,字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。,每一个抽象字符都会对应一个唯一的codepoint,常见字符集有:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。
使用1个字节编码的字符集,叫做单字节字符集(SBCS - Single-Byte Character Set)。
使用1、2、3、4等不等字节编码的字符集,叫做多字节字符集(MBCS - Multi-Byte Character Set)。
三、编码的历史
早期的时候,计算机的字符编码并没有统一的标准,很多都是来自电报时产生的编码方式,如博多电码,霍勒内斯码等,
EBCDIC
1962年 AT&T将第一部商用远程通讯卫星-Telstar I 放入环绕地球的轨道。同年,IBM公司创建了一套编码标准,EBCDIC,根据早期打孔机式的二进化十进数(BCD, Binary Coded Decimal)排列而成,定义了256种不同的8位字符。
ASCII
1963年 ASCII作为EBDIC替代产品而发展起来。ASCII由96个大小写字母、数字加上32个非打印字符组成
ASCII编码只占用1个字节,标准 ASCII 码是 7 位编码,但为了凑足一字节,多出来的一位,最高位通常设置为0。
扩展Ascii码
ASCII的缺点就是表示的东西太少了,只能用于显示现代美国英语
因此人们便利用ASCII的第8位产生了新的编码方式,第一个iso-8859-1字符集。又叫:Latin-1 编码(西欧编码),扩展ASCII字符集使用8位(bits)表示一个字符,其中0-127字符及位置编码完全兼容ascii码。只是在128-255位置编入了新字符,解决了部份西欧语言的显示问题。
后来陆续出了iso-8859-2…-15字符集。都完全兼容ascii码。
由于扩展ASCII只是解决了部分西欧语言的显示问题,表示字符还是太少,对其他语言无能为力,因此各个国家又为自己国家的文字制定了一系类标准
GB2312
1980年,中国制定了GB2312-80,一共收录了 7445 个字符,包括 6763 个汉字和 682 个其它符号。
GB2312规定一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样就可以组合出大约7000多个简体汉字了。在这些编码里,还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。
GB2312使用了2个字节进行编码
GB13000
由于GB2312只收录了6763个汉字,一些GB2312推出以后才简化的汉字“啰”,镕”和一些罕见字并未收录进去,1993年,有出现了“GB 13000.1-93”,简称为GB13000。
GB13000使用2个字节进行编码,收录中国大陆、台湾、日本及韩国通用字符集的汉字,总共有20,902个。
GBK
GBK是对GB2312的扩展,最早实现于windows95简体中文版,使用2个字节进行编码,收录了 21886 个符号,它分为汉字区和图形符号区。汉字区包括 21003 个字符。
GB18030
由于GBK自身并非国家标准,只是曾由国家技术监督局标准化司、电子工业部科技与质量监督司公布为“技术规范指导性文件”。
而原始GB13000一直未被业界采用,所以2000年,国家推出了GB18030-2000,简称GB18030,技术上兼容GBK而非GB13000,取代了 GBK1.0,成了正式的国家标准。
该标准使用1,2,4个字节进行字符编码
最近版本已经收录了 70244 个汉字
规定PC平台必须支持 GB18030 ,对嵌入式产品暂不作要求。因此有的手机、MP3只支持 GB2312。
在技术编码方面上,演化顺序为:
ASCII ⇒ GB2312 ⇒ GBK ⇒ GB18030
Big5
Big5,又称为大五码或五大码,是使用繁体中文社区中最常用的字符编码标准,Big5使用2个字节进行编码,共收录13,060个汉字。
在这个时候,字符集和字符编码其实并没有完全区分开,直到UNICODE字符集的出现,字符集和字符编码这两个概念才区分的出来
UNICODE
每一个国家都有自己的一套编码方案,这些东西在本地使用并没有问题,当时一旦出现在网络,由于不兼容,互相访问的时候便会出现乱码了,为了解决这个问题,便产生了Unicode,
Unicode字符集(统一码、万国码、单一码、标准万国码),每个数字代表唯一的至少在某种语言中使用的符号。(并不是所有的数字都用上了,但是总数已经超过了65535,所以2个字节的数字是不够用的。)被几种语言共用的字符通常使用相同的数字来编码,除非存在一个在理的语源学(etymological)理由使之不这样做。
unicode定义了17个平面,每个平面包括65536个码位
平面0 (0000-FFFF)0-65536的码位叫做基本多文本平面(BMP),其余的16个平面叫做辅助平面,
UTF-32字符编码
上述使用4字节的数字来表达每个字母、符号,或者表意文字(ideograph),每个数字代表唯一的至少在某种语言中使用的符号的编码方案,称为UTF-32。UTF-32又称UCS-4是一种将Unicode字符编码的协定,对每个字符都使用4字节。就空间而言,是非常没有效率的。
这种方法有其优点,最重要的一点就是可以在常数时间内定位字符串里的第N个字符,因为第N个字符从第4×Nth个字节开始。虽然每一个码位使用固定长定的字节看似方便,它并不如其它Unicode编码使用得广泛。
UTF-16字符编码
尽管有Unicode字符非常多,但是实际上大多数人不会用到超过前65535个以外的字符。因此,就有了另外一种Unicode编码方式,叫做UTF-16,UTF-16将0–65535范围内的字符编码成2个字节,如果真的需要表达那些很少使用的"星芒层(astral plane)"内超过这65535范围的Unicode字符,则需要使用一些特殊的技巧来实现。UTF-16编码最明显的优点是它在空间效率上比UTF-32高两倍,因为每个字符只需要2个字节来存储(除去65535范围以外的),而不是UTF-32中的4个字节。
UTF-16的缺点是每个字符都需要使用了2个字节来表示,因此并不能和ASCII兼容。
关于BOM
因为UTF-32和UTF-16使用4字节或字节进行编码,因此传输的时候便会出现字节序的问题,例如“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?这是UTF-16文件开头的BOM就有作用了。为了解决这个问题,多字节的Unicode编码方式定义了一个"字节顺序标记(Byte Order Mark)",它是一个特殊的非打印字符,你可以把它包含在文档的开头来指示你所使用的字节顺序,FEFF。如果收到一个以字节FF FE开头的UTF-16编码的文档,你就能确定它的字节顺序是单向的(one way)的了;如果它以FE FF开头,则可以确定字节顺序反向了。
UTF-8字符编码
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码(定长码),也是一种前缀码。它使用一至四个字节进行字符编码,可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节和ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部份修改,即可继续使用。因此,它逐渐成为电子邮件,网页和其他储存或传送文字的应用中,优先采用的编码。互联网工程小组(IETF)要求所有互联网都必须支持UTF-8编码。utf8的编码中也有bom,EF BB BF,不过由于utf8没有字节序的问题,所以这个可以用了确认这个文件是用utf8编码的
优点
UTF-8是ASCII的一个超集。所以现存的ASCII文本不需要转换,也是一个合法的UTF-8字符串,为传统的扩展ASCII字符集设计的软件通常可以不经修改或很少修改就能与UTF-8一起使用。
缺点
因为每个字符使用不同数量的字节编码,所以寻找串中第N个字符是一个O(N)复杂度的操作 — 即,串越长,则需要更多的时间来定位特定的字符。同时,还需要位变换来把字符编码成字节,把字节解码成字符。
UTF-8字符编码规则
如果一个字节的第一位为0,那么代表当前字符为单字节字符,占用一个字节的空间。0之后的所有部分(7个bit)代表在Unicode中的序号也就是codepoint。
如果一个字节以110开头,那么代表当前字符为双字节字符,占用2个字节的空间。110之后的所有部分(5个bit)加上后一个字节的除10外的部分(6个bit)代表在Unicode中的序号。且第二个字节以10开头
如果一个字节以1110开头,那么代表当前字符为三字节字符,占用3个字节的空间。1110之后的所有部分(4个bit)加上后两个字节的除10外的部分(12个bit)代表在Unicode中的序号。且第二、第三个字节以10开头
如果一个字节以11110开头,那么代表当前字符为四字节字符,占用4个字节的空间。11110之后的所有部分(3个bit)加上后两个字节的除10外的部分(12个bit)代表在Unicode中的序号。且第二、第三个字节以10开头
Byte1 | Byte2 | Byte3 | Byte4 |
0XXX XXXX | |||
110X XXXX | 10XX XXXX | ||
1110XXXX | 10XX XXXX | 10XX XXXX | |
1111 0XXX | 10XX XXXX | 10XX XXXX | 10XX XXXX |
例如
utf8编码对应的十六进制 | utf8编码对应的二进制 | 在Unicode字库序号的二进制 | 在Unicode字库序号的十六进制 | |
百 | e799 be | 11100111 10011001 10111110 | 0111011001111110 | 767E |
度 | e5ba a6 | 11100101 10111010 10100110 | 0101111010100110 | 5EA6 |
关于UTF8和UTF8 mb4
MySQL 5.5.3版本开始 MySQL中支持UTF8和UTF8mb4
UTF8mb4是UTF8的超集,MySQL 5.5.3之前的UTF8最多占用3个字节,UTF8mb4是对UTF8的扩充,最多占用4个字节
四、一个实例
我们创建一个文本文件,内容如下,并把它保存成utf8的格式
然后我们用UltraEdit打开后查看其16进制的内容
最前面的EF BB BF 表示这个文件是用utf8编码的
因为UTF-8是ASCII的一个超集。所以现存的ASCII文本不需要转换,也是一个合法的UTF-8字符串
对应1,2,3,4,5,6,7,8 ,\r\n原有的ASCII就是其合法的编码
31 32 33 34 35 36 37 38是12345678对应的编码
0D 0A是windows下的换行符\r\n
61 62 63 64 65 66 67是abcdefg对应的编码
0D 0A是windows下的换行符\r\n
对于E7 99 BE E5 BA A6通过上面的介绍我们可以知道其对应着百度两个字
utf8编码对应的十六进制 | utf8编码对应的二进制 | 在Unicode字库序号的二进制 | 在Unicode字库序号的十六进制 | |
百 | e799 be | 11100111 10011001 10111110 | 0111011001111110 | 767E |
度 | e5ba a6 | 11100101 10111010 10100110 | 0101111010100110 | 5EA6 |
五、参考文献
http://cenalulu.github.io/linux/character-encoding/ 十分钟搞清字符集和字符编码
http://tgideas.qq.com/webplat/info/news_version3/804/808/811/m579/201307/218730.shtml 字符编码的前世今生
http://blog.csdn.net/gqqnb/article/details/6266542 精确解释Unicode
http://superuser.com/questions/537229/what-character-encodings-were-used-before-1963
https://zh.wikipedia.org/wiki/%E7%BC%96%E7%A0%81
http://www.crifan.com/files/doc/docbook/char_encoding/release/htmls/enc_eascii_iso8859.html