浅谈文字编码和Unicode

ASCII编码:

计算机的历史上,由于计算机是美国人发明的,英文是美国人的母语,英文无非就是一些大小写英文字母、数字和一些符号,比较少,只有127个字符,总所周知,1字节=8bit,用1个字节可以完全表示所有英文,所以最初美国人将这127个字符被编码到计算机中,这就出现了ASCII编码

ASCII编码表:

各国语言编码:

由于ASCII编码只是为英文所用,其他国家的语言无法使用,所以其他国家自己搞了一套适用于自己语言的编码。

比如我们中国前前后后主流的编码就有GBK和GB2312和GB18030,GB2312收录6千多汉字及符号,包含了大量常用的汉字,但还是有很多生僻字没有收录,具有局限性,正因为GB2312的这些问题,国家标准化委员会又制定了GB13000,因早期的计算机中的汉卡采用了GB2312,无法顺利向GB13000过渡,所以GB13000变成了一个纸面上的 标准,无法推广。演变到后面,出现了最主流的中文编码GBK,它兼容GB2312标准,同时在GB2312标准的基础上扩展了GB13000包含的字,由于被window所采用,该标准得到了迅速推广。

一点小知识:GBK 即汉字内码扩展规范,K 为汉语拼音 Kuo Zhan(扩展)中“扩”字的声母,GBK的编码占两个字节

汉字编码表:https://www.cnblogs.com/whiteyun/archive/2010/07/06/1772218.html

你可以想得到的是,全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。浏览器我们经常出现乱码就是因为选择了具有局限性的语言编码所导致

统一编码Unicode:

首先说明Unicode和ASCII编码的区别:unicode是2字节,ascii是1字节,比如字母"a"用ascii表示为01000001,unicode则在前面补0,表示为00000000 01000001

如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。例如收录一个字符串“A3中¥”,我们用固定长度的三字节来存储,按照unicode编码在内存的存储形式为:

灰色部分为被浪费掉的内存空间,可见如果纯英文内存浪费有多严重。如果我们能够把灰色部分都压缩掉,将大大节省内存空间,如下图:

但是又出现新的问题:如果不告诉你,你怎么知道2A表示一个字符,而不是2A31或者2A31DA才表示一个字符呢,为了能让计算机知道2A是一个字符,DA49是一个字符,必须让不同的字符编码有不同的特征,可以让计算机根据这些特征去识别不同的字符。科学家想出了一种转换方案:字符编号在存储之前先转换为有特征的、容易定位的编号,读取时再按照相反的过程转换成字符本来的编号,根据这种转换方案诞生了UTF。

Unicode转换格式UTF

UTF 是 Unicode Transformation Format 的缩写,意思是“Unicode转换格式”,后面的数字表明至少使用多少个比特位(Bit)来存储字符。所以UTF-8就是采用至少8个比特位来存储字符。8个比特位即1个字节,事实上UFT-8是一种变长的编码方案,使用 1~6 个字节来存储。

先来看看UTF-8的编码规则:

UTF-8 的编码规则很简单:如果只有一个字节,那么最高的比特位为 0;如果有多个字节,那么第一个字节从最高位开始,连续有几个比特位的值为 1,就使用几个字节编码,剩下的字节均以 10 开头。

 

具体的表现形式为:

 

0xxxxxxx:单字节编码形式,这和 ASCII 编码完全一样,因此 UTF-8 是兼容 ASCII 的;
110xxxxx 10xxxxxx:双字节编码形式;
1110xxxx 10xxxxxx 10xxxxxx:三字节编码形式;
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字节编码形式。

xxx 就用来存储 Unicode 中的字符编号,不够位数前面补0。unicode转换为UTF-8的方式是根据字节的最高位是 0 还是 1 来判断字符到底占用了几个字节。

 

下面是一些字符的编码实例:

字符Næ
Unicode 编号(二进制)010011101110011000101110 11101100
Unicode 编号(十六进制)4EE62E EC
UTF-8 编码(二进制)0100111011000011 1010011011100010 10111011 10101100
UTF-8 编码(十六进制)4EC3 A6E2 BB AC

 

从上面的表格可以看出,举例“齐”这个字符,它的Unicode码是00101110 11101100,需要补充到UTF-8位数有14位,显示单字节编码形式和双字节编码形式都无法满足,因为单字节0xxxxxxx的x只有7位,双字节110xxxxx 10xxxxxx只有11位,只有三字节编码形式1110xxxx 10xxxxxx 10xxxxxx能满足,所以“齐”的UTF-8编码为11100010 10111011 10101100,不够位数前面补0。所以齐写入内存时,Unicode编号通过UTF-8编码转化后将11100010 10111011 10101100写入,当读取时计算机识别到第一个字节最高位是1,而且后续两个字节的最高位也是 1,就会把紧挨着的这三个字节E2 BB AC作为一个字符编号处理,再将UTF-8转成Unicode编码显示出来,这就是UTF的转换过程。

UTF-16和UTF-32与UTF-8的区别:

UTF-16就是采用至少16个比特位来存储字符,所以UTF-16的最小字节时2个字节,事实上UTF-16采用的时2字节或4字节来存储,对于 Unicode 编号范围在 0 ~ FFFF 之间的字符,UTF-16 使用两个字节存储,并且直接存储 Unicode 编号,不用进行编码转换。对于 Unicode 编号范围在 10000~10FFFF 之间的字符,UTF-16 使用四个字节存储

UTF-32 是固定长度的编码,始终占用 4 个字节,足以容纳所有的 Unicode 字符,所以直接存储 Unicode 编号即可,不需要任何编码转换。虽然浪费了空间,但无需转换,提高了效率。

这里UTF-16,UTF-32都时不需要做编码转换的,却都是属于UTF,但UTF又是Unicode转换格式的意思,理应是需要编码转换的,这点有点匪夷所思,值得深究。。

总结:

编码开始于简单的为英文服务的ASCII编码,但譬如中文等其他国家语言无法兼容,而出现了各国语言编码,各国语言混合在一起,就会出现乱码现象,这时候Unicode的出现是为了将各国语言统一用Unicode一种编码,可是Unicode一般是两个字节,如果是纯英文,相比ASCII只需一个字节会造成极大的内存浪费,UTF作为Unicode的转换格式应运而生,将其压缩转换为计算机能识别字符特征的编码,其中最主流的是UTF-8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值