乱码和中文编码的关系(ASCII码,unicode,UTF-8的前世今生)

名词解释
  • 位:计算机存储中的最小的计算单位,称为位(bit),音译比特,二进制中的一个 0 或 一个1 称为一位。

  • 字节:字节(Byte) 是一种计量单位,表示数据多少,计算机存储的计量单位,8 个二进制位组成一个字节,在 ASCII 编码中一个标准的字母(不区分大小写)占一个字节位,一个标准的汉字占两个字节位。

  • 字符:字符是计算机中使用的文字和符号,例如:“1、2、3、a、b、C、D、~!·#¥%…*()+”等等

ASCII 码介绍

ASCII码(American Standard Code for Information Interchange,美国信息交换标注码)是目前计算机中使用最广泛的字符集及其编码,由美国国家标准局(ANSI)制定。它已被国际标注化组织(ISO)定位国际标注,成为 ISO 646 标准。 ASCII 字符集由控制字符和图形字符组成。

在计算机存储单元中,一个 ASCII 码值占一个字节(8个二进制位),其最高位(b7)用作奇偶校验。所谓奇偶校验,是指在代码传送的过程中用来检验是否出现错的一种方法,一般分奇校验和偶校验两种。奇校验规定:正确的代码一个字节中 1 的个数必须是奇数,若非奇数,则在最高位 b7 添 1。偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位 b7 添 1。ISO 8859 的全称是 ISO/IEC 8859,是国际标准化组织及国际电工委员会(IEC)联合制定的一系列的 8 位字符集的标准,已经定义了 15 个字符集。

Unicode 介绍

Unicode 是一种在计算机上使用的字符编码。他是 http://www.unicode.org 制定的编码机制,要将全世界的常用文字都囊括进去。Unicode 为每种语言中的每个字符设定了统一且唯一的二进制编码,以满足跨语言跨平台进行文本转换和处理的需求。1990 年开始研发,1994 年正式发布。随着计算机计算能力的增强,Unicode 得到普及。

从 Unicode 2.0 开始,Unicode 采用了和 ISO 10646-1 相同的字库和字码,ISO 也承诺 ISO 10646 将不会给超出 0x10FFFF 的 UCS-4 编码赋值,使得两者保持一致。

Unicode 的编码方式与 ISO 10646 的通用字符集概念相对应,目前实际应用的 Unicode 的版本对应 UCS-2,使用 16 位的编码空间,保留了大量的空间作为特殊使用或将来扩展。

一个字符的 Unicode 编码是确定的,但是在实际传输过程中,由于不同系统平台的设计不一致,以及节省空间的目的,对 Unicode 编码的实现方式有所不同。Unicode 的实现方式成为 Unicode 转换格式(Unicode Translation Format,UTF)

UTF 的两种实现模式如下:

  • UTF-8:8位变长编码,对于大多数常用字符集(ASCII 中 0-127 字符),它只使用单字节,而对其他常用字符(特别是中文,日文,韩文等象形文字),它使用 3 字节。
  • UTF-16:16 位编码,是变长编码,大致相当于20位编码,值在 0 到 0x10FFFF 之间,基本上就是 Unicode 编码的实现,于 CPU 字序有关。

汉字编码有如下 4 种:

  • GB2312 字集是简体字集,全称为 GB2312(80) 字集,包括国标简体汉字 6763 个。
  • BIG5 字集是中国台湾地区的繁体字集,包括国标繁体汉字 15053 个。
  • GBK 字集是简繁字集,包括 GB 字集、 BIG5 字集和一些符号,共 21003 个。
  • GB18030 是国家制定的一个强制性大字集标注,全称为 GB18030-2000,它的推出使汉字集有了一个“大一统”的标准。

BOM —— Unicode 规范中推荐的标记字节顺序的方法是 BOM(Byte Order Mark)。在 UCS 编码中有一个叫做 “ZERO WIDTH NO-BREAK SPACE” 的标记,它的编码是 FEFF。而 FFFE 在 UCS 中是不存在的字符,所以不应该出现在实际的数据中。UCS 规范建议在传输字节流前,先传输标记 “ZERO WIDTH NO-BREAK” 。如果接受者接收到 FEFF,就表明这个字节流是 Big-Endian 的;如果接收到 FFFE,就表明是 Little-Endian 的。因此标记 “ZERO WIDTH NO-BREAK SPACE” 又被成为 BOM。Windows 就是使用 BOM 来标记文本文件的编码格式的。

用个例子区分一下 Big-Endian 和 Little-Endian,汉字 “严” 的 Unicode 码是 4E25,需要两个字节来存储,4E 需要一个字节存储 ,25 需要一个字节存储。4E 在前,25 在后,就是 Big Endian 方式;25 在前,4E 在后,就是 Little Endian 方式。

Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且FF比FE大1。

如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

举个例子,还是“严”字,在不同的编码下的编码方式

  • ANSI:文件的编码是两个字节 D1 CF ,正是在 GB2312 下的编码。
  • Unicode:编码是 4 个字节, FF FE 4E 25 ,其中 FF FE 表明是小头方式,真实的编码是 4E 25。
  • Unicode Big_Endian:编码是 4 个字节 FE FF 4E 25 ,其中 FE FF 表明是大头方式,真实的编码是 4E 25。
  • UTF-8:编码是六个字节 EF BB BF E4 B8 A5,前三个字节EF BB BF表示这是UTF-8编码,后三个 E4 B8 A5 就是严的具体编码,它的存储顺序与编码顺序是一致的。

ASCII 编码和 Unicode 编码的区别

ASCII 编码是 1 个字节,而 Unicode 编码通常是 2 个字节

  • 字母 A 用 ASCII 编码是十进制的 65、二进制的 01000001;
  • 字符 0 用 ASCII 编码是十进制的 48、二进制的 00110000,注意字符’0’和整数 0 是不同的;
  • 汉字“中”已经超出了 ASCII 编码的范围,用 Unicode 编码是十进制的 20013、二进制的01001110 00101101。

你可以猜测,如果把 ASCII 编码的 A 用 Unicode 编码,则只需要在前面补 0 就行,因此 A 的 Unicode 编码是 00000000 01000001。

新的问题又出现了:如果统一成 Unicode 编码,则乱码问题从此消失了。但是,如果你写的文本基本全都是英文,Unicode 编码比 ASCII 编码存储空间多了一倍,在存储和传输上很不划算

虽然现在空间不在是瓶颈,但本着节约的精神,还是应该把 Unicode 编码转换成“可变长编码“的 UTF-8 编码。UTF-8 编码把一个 Unicode 字符根据不同的数字大小编码成 1-6 个字节,常用的英文字母被编码成 1 个字节,汉字通常是 3 个字节,只有很生僻的字符才会被编码成 4-6 个字节。如果要传输的文本包含大量的英文字符,则用 UTF-8 编码就能省很大的空间,如下表:

字符ASCIIUnicodeUTF-8
A01000001000000000 0100000101000001
x01001110 0010110111100100 10111000 10101101

从上面的表格可以看出 ASCII 编码可以看做 UTF-8 的一部分,所以历史上遗留的只支持 ASCII 编码的软件,可以在 UTF-8 下得到有效的解决了。

搞清了 ASCII 、Unicode 和 UTF-8 的关系和区别,就可以总结一下现在计算机系统通用字符编码工作方式

  • 在计算机内存中,统一使用 Unicode 编码,当需要保存到硬盘或者传输时就转换为 UTF-8 编码。
  • 用记事本编辑时,从文件读取的 UTF-8 字符被转换成 Unicode 字符保存到内存里,编辑完成后,再把 Unicode 转换成 UTF-8 保存到文件,如下图所示

image

浏览网页时,服务器会把动态生成的 Unicode 内容转换成 UTF-8 在传输到浏览器,如下图所示:

image

喜欢编程的小伙伴关注微信公众号:yanjoo
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值