字符编码(ASCII,Unicode,GBK,UTF-8)

前言

你是否也经历过乱码的折磨,这两天被各种字符编码搞疯了,越看越糊涂,这里总结一下。首先说一下我们为什么这些编码,大家都知道计算机内部是都是二进制表示的,所以我们日常生活中的字符都不能直接存储到计算机内存里面,都要经过编码转换成二进制后才能存入计算机内存。关于同样的编码在不同的编码方式下对应的字符完全不一样。这里对这两天了解的ASCII、Unicode、GBK、UTF-8做一个小结。

ASCII

在早期美国首先就制定了ASCII(美国信息交换标准代码),它对英文字母、数字、一些常用符号和一些控制字符进行了编码,每个字符用一字节存储。在美国是够用了,但后来计算机传入其他国家后就出现了乱码。于是其他国家就纷纷开始制作自己国家的编码。

GB2312

中国最早的汉字编码是GB2312,台湾、香港、澳门等地也制定了繁体字的编码Big5。其中GB2312收录了6763个汉字和中文标点符号等等之类的图形符号682个,一个字节最多只能表示255,对于汉字来说根本就不够,所以GB2312里面就决定采用两个字节存储一个汉字。当然咱们有也还是要用字母那些,所以就兼容了ASCII编码,就是说GB2312里面的编码都是从ASCII编码后面开始排的。

GB2312编码方式

在使用GB2312的程序中,通常采用EUC储存方法。每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”(也称"区字节")从0xA1到0xF7,第二个字节称为“低位字节”(也称“位字节”)从0xA1到0xFE。然后加上它对应的区位码就得到了最后的GB2312编码。
例如 “啊”字是GB 2312之中的第一个汉字,它的区位码是1601。
所以高字节为: 0xA0+16=0xB0;低字节为:0xA0+1=0xA1;所以它对应的编码为:0xB0A1。

GBK

GB2312以及实现了中文的显示,但是有用过的人都应该能感受到它所包含的汉字还不够我们能够自由的表达。所以GBK又继续对GB2312实现了扩展,因此它完全兼容GB2312。

GBK 规范收录了 ISO 10646.1 中的全部 CJK 汉字和符号,并有所补充。具体包括:

  1. GB 2312 中的全部汉字、非汉字符号。
  2. GB 13000.1 中的其他 CJK 汉字。以上合计 20902 个 GB 化汉字。
  3. 《简化字总表》中未收入 GB 13000.1 的 52 个汉字。
  4. 《康熙字典》及《辞海》中未收入 GB 13000.1 的 28 个部首及重要构件。
  5. 13 个汉字结构符。
  6. BIG-5 中未被 GB 2312 收入、但存在于 GB 13000.1 中的 139 个图形符号。
  7. GB 12345 增补的 6 个拼音符号。
  8. 汉字“〇”。
  9. GB 12345 增补的 19 个竖排标点符号(GB 12345 较 GB 2312 增补竖排标点符
    号 29 个,其中 10 个未被 GB 13000.1 收入,故 GBK 亦不收)。
  10. 从 GB 13000.1 的 CJK 兼容区挑选出的 21 个汉字。
  11. GB 13000.1 收入的 31 个 IBM OS/2 专用符号。
    12.未录入《新华字典》上的一些字,如“韡”的简体。

在GBK之后,我国又推出了GB18030-2000和GB18030-2005,分别在2000年和2005年发布。它支持ISO国际标准。

Unicode

后面呢,人们发现自己的编码是有了,但自己如果要是和其他国家的好朋友发消息依然还是乱码呀,有没有一种编码可以同时容纳世界上所有的字符呢。这时候Unicode就出现了,它就给全世界所有的字符都编了个号,比如汉字码的Unicode编码为:7801,对应的二级制编码就是:0111 1000 0000 0001,可以看出它至少要两个字节才能存储,而其他更长的编码可能要三字节,四字节。

Unicode的问题

虽然字符是编码是解决了,但现在有个问题就是计算机怎么知道接下来读取几个字节对应一个字符呢。如果统一都用三字节或者四字节,但是对于英文字母一个字节就够了,这又让人家不高兴了,同样的信息要画额外三倍的内存存储。

UTF-8

为了解决Unicode存储方式这个问题,于是就出现了UTF-8(Unicode Transformation Format),它是针对Unicode的一种可变长度字符编码。它最大的特点就是长度可变,它可以同时用1~4字节表示一个符号,它是Unicode的实现方式之一。

UTF-8编码方式

1、对于单字节的字符来说就和原来的ASCII码一样。
2、对于多字节的字符,它在第一个字节高位设置有几个1就表示该字符有几个字节。其后的每个字节都以10开头,其余位置则用该字符对于Unicode编码填充。比如:
0xxxxxxx 一个字节的字符
11xxxxxx 10xxxxxx 两个字节的字符
111xxxxx 10xxxxxx 10xxxxxx 三个字节的字符
1111xxxx 10xxxxxx 10xxxxxx 10xxxxxx 四个字节的字符
码的Unicode编码:
十六进制:7801
二进制:01111000 00000001
UTF-8:11100111 10100000 10000001

从上面的例子容易看出,如果计算机读取到第一个字节是0,则该字节就表示一个字符,如果第一个字符是1,则继续查找其后有n个1,然后再读取其后的n个字节,最后再转码得到对应字符。

续:

编码设置与实际数据

前面介绍了各种编码方式,我们经常看到每个编辑器都有设置编码的功能。有时候对于一份乱码的文件我们可能修改一下文件的编码就正常显示了,是在在内存中的二进制数据并没有改变,所以我们的编码设置和实际存储的数据是一个怎么样的关系呢?

通过前面的内容可以了解到产生不同编码的原因是为了显示不同内容,也可以说是对ASCII的扩展,对于ASCII字符,无论是使用GB2312还是GBK其编码都是一样的,但是对于汉字其编码就可能不一样了。所以实际上我们的设置编码只是给计算机指定这一串二进制流该怎么读取方式。当我们设置了一个txt文本编码是GBK,它读取二进制中第一个字节是0x30(0),可以直接识别出是字符0,读到第二个字节是0xdf,这时候如果是ASCII编码就会出现乱码了,但现在是GBK,所以它会继续读取第二个字符,如果是0x5c,然后它再去码表中查找对应的字符,最后找到是汉字運,就显示出来,若没有找到对应的字符则显示乱码。

如果有错的地方还望大家指出。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值