欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

字符编码的故事

程序员文章站 2022-03-31 14:51:38
...

字符编码的故事

不管是以前用 C#。 还是现在用 javascript.

一直对于字符编码这回事儿,一直不清楚.

在读 阮一峰写的ES6入门的时候,讲到了字符编码. 于是趁着学习这个的机会了解一下。

  1. ascii
  2. unicode
  3. utf-8
  4. utf-16

我们都知道 一个字节(Byte) = 8位(bit)

所谓字节,原意就是用来表示一个完整的字符的。

最初的计算机性能和存储容量都比较差,所以普遍采用4位BCD编码(这个编码出现比计算机还早,最早是用在打孔卡上的)。BCD编码表示数字还可以,但表示字母或符号就很不好用,需要用多个编码来表示。后来又演变出6位的BCD编码(BCDIC),以及至今仍在广泛使用的7位ASCII编码。不过最终决定字节大小的,是大名鼎鼎的System/360。当时IBM为System/360设计了一套8位EBCDIC编码,涵盖了数字、大小写字母和大部分常用符号,同时又兼容广泛用于打孔卡的6位BCDIC编码。System/360很成功,也奠定了字符存储单位采用8位长度的基础,这就是1字节=8位的由来。



ASCII

一切的开始.

ASCII第一次以规范标准的型态发表是在1967年,最后一次更新则是在1986年,至今为止共定义了128个字符;其中33个字符无法显示(一些终端提供了扩展,使得这些字符可显示为诸如笑脸扑克牌花式等8-bit符号),且这33个字符多数都已是陈废的控制字符。控制字符的用途主要是用来操控已经处理过的文字。在33个字符之外的是95个可显示的字符,包含用键盘敲下空白键所产生的空白字符也算1个可显示字符(显示为空白)。


ASCII 长度是(2的8次方) 也就是 256.

其中33个字符无法显示(一些终端提供了扩展,使得这些字符可显示为诸如笑脸扑克牌花式等8-bit符号),且这33个字符多数都已是陈废的控制字符


一些奇怪的控制命令. 可能现在已经不怎么用了

0-31&127都是控制字符.

32-126包含标点,英文字符,运算符号之类的.


如果只是英文的话. 这个是ok的.

可是世界上还有其他的文字.

正好0-127还剩下128-255,可以用来扩展字符.


可是你拉丁字母,欧洲的一些语言扩展可以.

亚洲,中文,日文,韩文之类的另一种语系. 就完全没办法了.

于是中国自己扩展了一套.

127之前的我们都不动. 后面高于127的,两个字符连起来. 组成一个汉字.

每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”,第二个字节称为“低位字节”。

“高位字节”使用了0xA1–0xF7(把01–87区的区号加上0xA0),“低位字节”使用了0xA1–0xFE(把01–94加上0xA0)。 由于一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0–0xF7,“低位字节”的范围是0xA1–0xFE,占用的码位是72*94=6768。其中有5个空位是D7FA–D7FE。

这就是很久以前,我在网吧上的时候,网页编码选项里面的GB2312


可是这个依然不够,生僻汉字. 少数民族也有自己的文字.

字符有一字节和双字节编码,007F范围内是第一个字节,和ASCII保持一致,此范围内严格上说有96个文字和32个控制符号。

之后的双字节中,前一字节是双字节的第一位。总体上说第一字节的范围是81FE(也就是不含80FF),第二字节的一部分领域在407E,其他领域在80FE

就是说。 第一个字节稍微遵守一下. 必须大于 0x80.

第二个字节就随你弄了. 介个就是GBK



unicode

ASCII 这么多种扩展. 比如我想浏览其他国家的网站,那就是乱码咯.

除非我有他的编码,而且匹配上了.

做软件啊 之类的更是. 你要卖到其他国家去. 就得各种版本的字符都得弄.

于是有人受不了了 弄了一个UNICODE


定长. 2是两个字节. 也就是(2的16次方) 65536,满足日常需求.

可是也有一个问题.

它保持了以前 ASCII 编码 前 127 位不变. 但是现在是定长 2个字节,所以 前面就只能用 0 来补位. 如果英文传输的话,浪费巨大.



UTF-8

  • 对于UTF-8编码中的任意字节B,如果B的第一位为0,则B独立的表示一个字符(ASCII码);
  • 如果B的第一位为1,第二位为0,则B为一个多字节字符中的一个字节(非ASCII字符);
  • 如果B的前两位为1,第三位为0,则B为两个字节表示的字符中的第一个字节;
  • 如果B的前三位为1,第四位为0,则B为三个字节表示的字符中的第一个字节;
  • 如果B的前四位为1,第五位为0,则B为四个字节表示的字符中的第一个字节;

以上就是 UTF-8 的实现方式.

有一个原则必须说明,之前百度的时候发现了很多问题,在问 unicodeutf-8 的区别.

unicode 是一个字符集(规定你这个 xxxxxxxx yyyyyyy 代表啥)

utf-8 是这个字符集的一种实现编码方式而已.

完全是不同的东西.


Unicode符号范围 | UTF-8编码方式

(十六进制) | (二进制)

--------------------+---------------------------------------------

0000 0000-0000 007F | 0xxxxxxx

0000 0080-0000 07FF | 110xxxxx 10xxxxxx

0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx

0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

第一位是0 就是和 ASCII码一样。一个字节.

后面的根据字符范围来分段显示.

第一个字符有多少个1就有多少个字符 + 0. 后面所有字符前面初始都是10.

就拿一个

unicode

(16) 6211
(2) 110001000010001

转换成 UTF-8

(unicode)110001000010001
(utf-8) 11101100 10010000 106211

这样就转换为utf-8

优点

ASCII 容.

英文占用少。 便于网络传输.

容易识别,轻易的知道后面字符串的长度。

缺点

中文传输,占用大。

wiki上还说了不少其他缺点。 至少我用不上。

UTF-16


UTF-16是Unicode字符编码五层次模型的第三层:字符编码表(Character Encoding Form,也称为"storage format")的一种实现方式。即把Unicode字符集的抽象码位映射为16位长的整数(即码元)的序列,用于数据存储或传递。Unicode字符的码位,需要1个或者2个16位长的码元来表示,因此这是一个变长表示。

首先 UTF-16 是变长的.


编码方式

小于 U+FFFF

就基于 Unicode 2个字节

大于 U+FFFF

例如U+10437编码(????):
0x10437减去0x10000,结果为0x00437,二进制为0000 0000 0100 0011 0111。
分区它的上10位值和下10位值(使用二进制):0000000001 and 0000110111。
添加0xD800到上值,以形成高位:0xD800 + 0x0001 = 0xD801。 添加0xDC00到下值,以形成低位:0xDC00 +
0x0037 = 0xDC37。
下表总结了该转换,以及其它。颜色指示如何从码点位被分布在所述的UTF-16字节。由UTF-16编码过程中加入附加位以黑色显示。

上面是 wiki 的一个实例。

也就是。

先减去 0x10000 得到结果 0xD800 | (高位10)0xDC00 | 低位(10)

结果就是 两个16进制4位.



当然。 在查资料的时候,自己也明白还是有很多东西不明白. 不过基本知识了解了,目前够用了。 以后用到遇到问题再查吧


  1. 中文占多数的时候使用 UTF-16

因为大部分时候都能固定2个字节,存储效率高.

  1. E文占多数的时候自然就是 UTF-8

因为 E文只要一个字节


问题来了。

存储文本的时候,很容易区分。

可是网络传输呢.

就算你中文多,图片也是要传输的. 这个也应该要算进去吧.

Gzip压缩后. 是否区别也不大?



感谢