中文字符编码的相互转换(一)

时间:2023-01-24 19:14:35
作为程序员,在日常的工作中总会遇到编码的知识。尤其是在前后台交互的过程中,字符编码如影随行。如果多个平台的字符编码不一致,需要相互转化的话,很有必要了解一下编码的工作原理。

网上有太多关于编码的知识了,在此我尽量按照我对编码的理解描述的简单易懂。

1,ASCII码

在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位是一个bit,有0和1两种状态。8个bit构成一个字节,也就是byte。这就是bit和byte的区别。

在日常使用中,存储的单位一般是byte,比如说到一个文件大小是2k,是说这个文件占用了2048个byte;一个内存条的容量为256M,说明该内存可以存储256*1024*1024个byte。网络传输的单位是bit,我们平常说到网络下行带宽1M,是说此网络在最好的情况下可以同时下载速度是每秒1024*1024个bit,换算成字节的话就是128k/s。

0和1各代表一个状态,一个byte有8个bit,总共可以表示2的8次方=256个状态。若是每个状态对应一个符号,一个byte可以表示256个符号,也就是从0000000到11111111。

在上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这就是大名鼎鼎的ASCII码了,一直沿用至今。此后虽然出现了各种各样的编码,但基本上都是兼容ASCII码的。

但ASCII码一共只规定了128个字符的编码,比如空格"SPACE"是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。

2,GB2312

英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。我们就以中文做例子,中国的汉字有10万左右,即使是常用字也有六七千,必须得用多个字节来表示。

最先诞生的是GB2312编码。其编码结构不用特别了解清楚,感兴趣的可以去网上搜索专门的文档。我们只需要明白以下几点:
1)该编码可以表示大概7000左右个字符。其中有中文及一些常见的拉丁字母等。基本可以覆盖我们日常打字使用。
2)该编码完全兼容ASCII码,计算机去读的时候首先判断最高位,如果是0,那么这个字符只占用一个字节,表示的内容跟ASCII码表示的一样。如果该字符最高位是1,那么该字节连同下一个字节表示一个中文汉字。所以平常咱们常说的英文一个字节,中文两个字节其实是从这里来的。

3,GBK

两个字节最多可以表示的字符数是 2的16次方=65536,如果要求首位必须是1,那么最多可以表示 32768 个字符,但是GB2312 只用了其中的7000左右的字符。这显然是没有做到物尽其用,而且如果有些特殊的中文,GB2312根本表示不了。所以GBK就应运而生了。

GBK 就尽量将能用到的状态都表示成中文字符了,当然最终还是有些状态没办法用(具体可以自行查找文档),最终可以表示23940个字符,其中有21003是汉字。

GBK是完全兼容GB2312的,所以GBK的应用是很广泛的,而且从Windows95开始,Windows的中文版默认中文支持就是GBK编码。

4,Unicode

GBK基本解决了中文编码问题,但另外一个大问题随之而来,那就是国际化。咱们按照此方式来表示简体中文,繁体中文怎么表示?日本和韩国他们的文字也没法弄。当然他们也利用最高位来做文章,发明了big5等兼容ASCII码的编码格式,但是这几种编码之间是并不兼容的。一段GBK编码的文件在*友人的电脑里打开就是乱码了。

这时候,Unicode就诞生了。

完全弄明白Unicode的细节是非常困难的,我们也是明白以下几点就够了:
1)Unicode编码是给世界上所有的符号都分配了一个码。GBK最多也只能表示3万多的汉字,康熙字典里面的大部分汉字都没法用GBK表示,但是Unicode就能,它可以表示这个星球上所有的符号。
2)Unicode有UCS-2和UCS-4两种编码,2和4都是代表字节的意思,也就是说前者用两个字节表示,后者用4个字节表示。所以,UCS-2的表示范围是65536个字符,而UCS-4则可以表示超过22亿个字符,我想这真的是可以表示所有的字符了。其实日常使用我们用的只是UCS-2,一般说的Unicode编码也是只它。它包含了所有的简体中文,现用的繁体中文,火星文,以及其他国家的现用文字。古籍中的文字就得去UCS-4中去找了。

5,UTF-8

很遗憾,Unicode并不是完美的。不完美的地方主要有两点:
1)不兼容ASCII码。因为Unicode是用两个字节表示,ASCII码范围内的字符都被扩充成了两个字节,前面又补了8个0。所以,如果你的电脑只支持Unicode编码的话,所有的英文资料全都没法阅读了。
2)占用的存储变大,如果涉及到传输,所耗费的流量也会变大。中文的表现一般,英文表现最明显。纯英文文本所消耗的存储比以前增大了一倍。

这个时候就出现了诸如UTF-8等实现方式。这里我们只讨论UTF-8,因为它是使用最广泛的。它弥补了Unicode的缺陷,所以一诞生就风靡全球了。UTF-8主要有以下几个优点。
1)UTF-8与Unicode是一一对应的。所以UTF-8是国际化的编码方式。
2)UTF-8是针对Unicode的可变长度字符编码,最短一个字节,最长3个字节,1个字节表示的就是ASCII码,所以UTF-8是完全兼容ASCII码的。
3)正是因为UTF-8的变长实现,解决了Unicode的存储多的问题。可能有朋友要问了,UTF-8最多需要用3个字节表示,而Unicode只需要两个,怎么能说UFT-8会省存储呢?因为目前英文是最通用的语言,大部分字符都是ASCII码。

但UTF-8并不是一点缺点也没有,因为变长表示,所以一段UTF-8编码没法一下子算出有多少个字符。而这一点能力对于以上几种编码格式来说是轻而易举的。所以当今世界上没有最完美的字符编码,只有最合适某个场景的编码。