常见编码的简单认识

在做测试时,经常会遇到很多乱码,因此想简单了解一下编码。
以下是对编码学习的一个记录。

常见的乱码

在这里插入图片描述

常见的各种编码
编码名称占用字节备注
ASCII一个字节8个比特位,共128个符号(其中32个控制符号)只使用了一个字节的后七位,加上0共128位,第一个比特位为统一规定为0
Gb23122个字节,第一个字节是高位字节,第二个字节是低位字节GB2312 对汉字进行了分区处理,每个区含有 94 个汉字或者字符,总共有 94 个区,每个汉字或者字符都对应一个 分区编号和分区内的位置编号,称为 区位码,ASCII 码为 0- 31 的这 32 个字符是不可显示的字符,为了避免和这些字符的码点冲突,将 分区编号和分区内位置编号都加上 32 ,把这个转换的结果称为 国标码,为了区分AScii表,将首位全部置为1,也就是加上128称为内码,汉字是以内码的形式在计算机中存储和传播的。内码 = 区位码 + 0xA0
GBK两个字节组成而GBK是GB2312的扩展不仅仅只是显示简体还有繁体等
GB18030每个字或字符可以由一个,两个或四个字节组成GB18030是32位的,它支持简体中文、繁体中文 藏文、蒙文、维吾尔文等主要的少数民族文字,包含GBK和GB2312。
BIG5两字节台湾地区的编码标准,主要是繁体字
ANSI美国国家标准对应每个国家的编码标准
base64一个字节或者说6个比特位只包含64个符号,一个字节只用后6位,高位补00,首先将图片或文字转为二进制,然后每6位分组,高位补00,不足6位低位补0
unicode四个字节包含全世界的文字的一个编码表
UTF-8变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其他实现方式还包括 UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示),不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8 是 Unicode 的实现方式之一

1字节= 8比特也就是8位二进制,也就是两位16进制数,与现在抓包和查看文件存储的形式16进制是相同的,参考ASCii表https://www.asciim.cn/,可以得知每个字节所代表的字符
在这里插入图片描述

一个汉字占两个字节,也就是16比特

ASCII

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

Gb2312

GB2312 把每个汉字都编码成两个字节,第一个字节是高位字节,第二个字节是低位字节

GB2312 为了兼容 ASCII ,其编码需要进行一些转换才能避免和 ASCII 编码重叠,转换的过程涉及到区位码和国标码的概念,下面说明转成内码的过程

  • 区位码

GB2312 对汉字进行了分区处理,每个区含有 94 个汉字或者字符,总共有 94 个区,每个汉字或者字符都对应一个 分区编号和分区内的位置编号,称为 区位码

比如:汉字 “中” 字的 分区编号是 54,分区内位置编号是 48,所以,“中” 字的区位码是 54 48

  • 国标码

国标码 也叫 交换码,用于交换文件所使用的编码,在早期,不同的操作系统可能使用不同的内码,如果它们之间要交换文件,则会发生乱码的现象,当时的解决方法是交换文件之前先转成交换码再交换,接收者收到之后再转成内码

交换码是比较早期的一种方案,目前系统大都采用内码作为交换码

ASCII 码为 0- 31 的这 32 个字符是不可显示的字符,为了避免和这些字符的码点冲突,将 分区编号和分区内位置编号都加上 32 ,把这个转换的结果称为 国标码

比如:汉字 “中” 字分区编号是 54,分区内位置编号是 48,加上 32 之后,分区编号是 54 + 32 = 86, ,分区内位置编号是 48 + 32 = 80,所以 “中” 字 的国标码是 86 80

  • 内码

国标码 和 ASCII 码还是存在一定的重复,比如 “中” 字 的国标码是 86 80,对应第一个字节是 86,第二个字节是 80,而在 ASCII 码中它们分别代表大写字母V 和 大写字母 P,这就无法区分它们到底是一个汉字,还是两个字母

为了解决这一点,把国标码中的每个字节的最高位置为 1,也即相当于每个字节都加上 128 ( 2的7次方 ),还是以 “中” 字为例,它的 国标码是 86 80,加上 128 后, 第一个字节是 86 + 128 = 214, 第二个字节是 80 + 128 = 208,转化成 16 进制是 0xD6 0xD0 ( 214 的十六进制是 0xD6, 208 的十六进制是 0xD0 )

国标码的每个字节都加上 128 后,得到国标码的机内码,简称 内码,汉字是以内码的形式在计算机中存储和传播的

上面介绍 区位码 和 国标码,主要是是为了说明 汉字内码是如何一步一步发展而来的

可以看出,汉字的 区位码 + 32 + 128 就得到了内码,进一步简化,区位码 + 32 + 128 = 区位码 + 160 = 区位码 + 0xA0(128 的十六进制) , 因此 内码 = 区位码 + 0xA0

比如:“中” 字的区位码是 54 48,对应的十六进制是0x36 0x30,因此它的内码为 (0x36 + 0xA0) (0x30 + 0xA0),也即 0xD6 0xD0

GBK

和 GB2312 一样,GBK 也是双字节编码,为了向下兼容 GB2312, GBK 使用了 GB2312 没有用到的编码区域,总的编码范围是: 第一个字节 0x81–0xFE,第二个字节 0x40–0xFE, 具体的编码范围细分如下
在这里插入图片描述

GB18030 编码

与 GBK 不同的是,GB18030 是变长多字节字符集,每个字或字符可以由一个,两个或四个字节组成,所以它的编码空间是很大的,最多可以容纳 161 万个字符

由于需要兼容 GBK,四个字节的前两个字节和 GBK 编码保持一致,GB18030 具体的编码范围如下

在这里插入图片描述

BIG5

是通行于台湾、香港地区的一个繁体字编码方案。虽然存在一些瑕疵,但广泛应用于电脑行业,尤其是互联网中,从而成为一种事实上的行业标准。

1983年10月,台湾国家科学委员会、教育部国语推行委员会、中央标准局、行政院共同制定了《通用汉字标准交换码》,后经修订于1992年5月公布,更名为《中文标准交换码》,BIG5是台湾资讯工业策进会根据以上标准制定的编码方案。

BIG5码是双字节编码方案,其中第一个字节的值在OXAO-OXFE之间,第二个字节在OX40-OX7E和OXA1-OXFE之间。

BIG5收录13461个汉字和符号,包括:

  • 符号408个,编码位置A140-A3BE
  • 常用字5401个,编码位置A440-C67E,包括台湾教育部颁布的《常用国字标准字体表》的全部汉字4808个,台湾教科书常用字587个,异体字6个。
  • 次常用字7652个,编码位置C940-F9D5,包括台湾教育部颁布的《次常用国字标准字体表》的全部汉字6341个,《罕用国字标准字体表》中使用频率较高的字1311个。
ANSI

美国国家标准协会,也就是说,每个国家(非拉丁语系国家)自己制定自己的文字的编码规则,并得到了 ANSI 认可,符合 ANSI 的标准,全世界在表示对应国家文字的时候都通用这种编码就叫 ANSI 编码。换句话说,中国的 ANSI 编码和在日本的 ANSI 的意思是不一样的,因为都代表自己国家的文字编码标准。比如中国的 ANSI 对应就是 GB2312 标准,日本就是 JIT 标准,香港,台湾对应的是 BIG5 标准等等。当然这个问题也比较复杂,微软从 95 开始,用就是自己搞的一个标准 GBK。GB2312 里面只有 6763 个汉字,682 个符号,所以确实有时候不是很够用。GBK 一直能和 GB2312 相互混淆并且相安无事的一个重要原因是 GBK 全面兼容 GB2312,所以没有出现任何冲突,你用 GB2312 编码的文件通过 GBK 去解释一定能获得相同的显示效果,换句话说:GBK 对 GB2312 就是,你有的,我也有,你没得的,我还有!

好了,ANSI 的标准是什么呢,首先是 ASCII 的代码你不能用!也就是说 ASCII 码在任何 ANSI 中应该都是相同的。其他的,你们自己扩展。所以呢,中国人就把 ASCII 码变成 8 位,0x7f 之前我不动你的,我从 0xa0 开始编,0xa0 到 0xff 才 95 个码位,对于中国字那简直是杯水车薪,因此,就用两个字节吧,此编码范围就从 0xA1A1 - 0xFEFE,这个范围可以表示 23901 个汉字。基本够用了吧,GB2312 才 7000 多个呢!GBK 更猛,编码范围是从 0x8140 - 0xFEFE,可以表示 3 万多个汉字。可以看出,这两种方案,都能保证汉字头一个字节在 0x7f 以上,从而和 ASCII 不会发生冲突。能够实现英文和汉字同时显示。

Base64

Base64,顾名思义,就是包括小写字母a-z、大写字母A-Z、数字0-9、符号"+“、”/"一共64个字符的字符集,(另加一个“=”,实际是65个字符,这个“=”作为填充符使用)。任何符号都可以转换成这个字符集中的字符,这个转换过程就叫做base64编码。

base64怎么转换

首先将字符串(图片等)转换成二进制序列,然后按每6个二进制位为一组,分成若干组,如果不足6位,则低位补0。每6位组成一个新的字节,高位补00,构成一个新的二进制序列,最后根据base64索引表中的值找到对应的字符。

Unicode

包含全世界的文字的一个编码表,Unicode 编码范围是:0-0x10FFFF,可以容纳 1114112 个字符,一共使用四个字节,32个比特位。

之前提到,Unicode 没有规定字符对应的二进制码如何存储。以汉字“汉”为例,它的 Unicode 码点是 0x6c49,对应的二进制数是 110110001001001,二进制数有 15 位,这也就说明了它至少需要 2 个字节来表示。可以想象,在 Unicode 字典中往后的字符可能就需要 3 个字节或者 4 个字节,甚至更多字节来表示了。

这就导致了一些问题,计算机怎么知道你这个 2 个字节表示的是一个字符,而不是分别表示两个字符呢?这里我们可能会想到,那就取个最大的,假如 Unicode 中最大的字符用 4 字节就可以表示了,那么我们就将所有的字符都用 4 个字节来表示,不够的就往前面补 0。这样确实可以解决编码问题,但是却造成了空间的极大浪费,如果是一个英文文档,那文件大小就大出了 3 倍,这显然是无法接受的。

于是,为了较好的解决 Unicode 的编码问题, UTF-8 和 UTF-16 两种当前比较流行的编码方式诞生了。当然还有一个 UTF-32 的编码方式,也就是上述那种定长编码,字符统一使用 4 个字节,虽然看似方便,但是却不如另外两种编码方式使用广泛。

UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其他实现方式还包括 UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示),不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8 是 Unicode 的实现方式之一。

UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8 的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

下表总结了编码规则,字母x表示可用编码的位:

Unicode符号范围(十六进制)UTF-8编码方式(二进制)
0000 0000-0000 007F0xxxxxxx
0000 0080-0000 07FF110xxxxx 10xxxxxx
0000 0800-0000 FFFF1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。

下面,还是以汉字严为例,演示如何实现 UTF-8 编码:

严的 Unicode 是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此严的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,严的 UTF-8 编码是11100100 10111000 10100101,转换成十六进制就是E4B8A5。

FFFF),因此严的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,严的 UTF-8 编码是11100100 10111000 10100101,转换成十六进制就是E4B8A5。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值