字符编码笔记(理论篇)

记录一下字符编码的有关事项,这篇文章先说说字符编码的一些历史和原理。

1.ASCII编码与ANSI标准

1字节(1B) = 8比特(8b) = 8个二进制位
1B的信息量 0b00000000 ~ 0b11111111 = 2^8 = 256个状态

标准ASCII编码使用1B的后7位,而第一位默认置0,即:
0b00000000 ~ 0b01111111 = 2^7 = 128个状态
这128个状态位存储了控制字符、数字、大小写字母和其他符号。详见ASCII编码表[]

渐渐地,128个状态不再能满足人们的需求,不同国家(语言区)都想把自己语言的字符编进ASCII编码中,于是人们纷纷自发的使用起了1B的另外128个状态,称为扩展ASCII编码,其使用1B的后7位,同时第一位默认置1,即:
0b10000000 ~ 0b11111111 = 2^7 = 128个状态
由于是自发行为,每个国家(语言区)都对扩展ASCII编码有自己独特的定义,因此彼此之间的扩展ASCII编码是不能通用的。(标准ACII编码区仍然通用)

麻烦还不止于此,部分国家(语言区)的字符数量众多(如汉字就是十万级别的数量),显然扩展ASCII编码的128个状态不能满足,于是有了下面的一种编码方式(ANSI标准编码):

  1. 保留标准ASCII编码的128个字符不变,称为半角
  2. 其余的字符用两个字节来表示,这样理论上能新增256*256=65536个编码,称为全角
    这也是大家最早所认知的下面这句话的由来

英文(半角)占一个字节,汉字(全角)占两个字节

全角字符中用于编码的两个字节被称为高位字节低位字节
全角字符 = 高位字节 + 低位字节
高位字节和低位字节都可以选择用三种策略编码:

  1. 标准ASCII编码的128个状态
  2. 扩展ASCII编码的128个状态
  3. 以上都用的256个状态

不难发现当这两个字节都使用标准ASCII编码的128个状态时,计算机是无法分辨这是两个半角字符,还是一个全角字符的。因此全角的编码区域实际上只有:
256*256 - 128*128 = 49152个
针对这个5万个左右的编码区,不同国家(语言区)制定了不同的编码标准,我们熟悉的有:

  • GB2312,大陆1980年标准(其中一级汉字3755个,二级汉字3008个,包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的全角字符682个。)
  • GBK,大陆1995年标准(GB2312的扩展,增加不常用汉字与字符,总编码量扩展到23940)
  • BIG-5,台湾标准

2. Unicode编码

随着互联网的发展,信息交流变得越来越频繁,这就促使一种“大一统”的编码方式出现。这种编码可以将世界上所有的字符都编入其中,且每个状态位和字符都唯一对应。正如它的名字代表的意思那样,Unicode编码做到了。
Unicode将编码存储这两个逻辑过程独立开来。

  • 世界上的每一个字符都有且只有一个Unicode编码方案即:字符S->Unicode(S)
  • 每一个Unicode码都可以通过的多种方案来存储,这些方案的名称即是我们常听到的UTF-8、UTF-16、UTF-32等等。

2.1 编码逻辑

下面先说一下Unicode的编码方式:
Unicode码的编码范围:0x000000 ~ 0x10FFFF
它的后四位称为一个plane:0x0000 ~ 0xFFFF = 2^16 = 65536个状态
前两位代表plane的编号,一共有:0x00 ~ 0x10 = 17个plane
所以Unicode编码一共有:17 * 65536 = 1114112个状态
这足以将世界上所有的字符都编码进去,而且还有很大的富余。同时别忘了,预留的空白plane可远远多于17个(16*16=256个)
事实上,在Unicode 5.0版本中只用到了0,1,2,14,15,16这几个编号plane中的238605个状态

2.2 存储逻辑

Unicode编码总算是将全世界的字符都“装”下了,当然为了达到此目的,经过Unicode编码后的字符所占空间变的很大。本来只占一个字节的普通ASCII字符和占两个字节的ANSI字符统统都变成了占三个字节的Unicode字符,造成了空间的极大浪费。因此Unicode编码的编码方式存储方式分开独立实现,存储传输方案专注于实现Unicode编码如何节省存储空间。
常见的存储传输方案有:UTF-8,UTF-16,UTF-32等

UTF-8方案

UTF-8最大的一个特点,就是它是一种变长的存储方式。它可以使用1~4个字节存储一个Unicode码,根据不同的Unicode码而变化存储字节的长度。
UTF-8的存储规则很简单,只有二条:

  1. 对于小于0x7F的Unicode码,UTF-8编码只有一个字节,字节的第一位设为0,后面7位为Unicode码。这也是为了英语字母的UTF-8编码和普通ASCII码是相同的。
  2. 对于其他Unicode码,落入下表的相应的范围中。其中x代表空白位,用Unicode码补充。
Unicode符号范围(十六进制) UTF-8存储方式(二进制)
000000 ~ 00007F 0xxxxxxx
000080 ~ 0007FF 110xxxxx 10xxxxxx
000800 ~ 00FFFF 1110xxxx 10xxxxxx 10xxxxxx
010000 ~ 10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-16方案

UTF-16方案也是一种变长存储方式,它采用两个字节或四个字节来存储Unicode码。
当Unicode码位于编号为00的plane(即0x000000 ~ 0x00FFFF之间)时,Unicode码正好对应了两个字节(16位二进制)的长度。即使用两个字节顺序存储。
当Unicode码位于其他编号的plane(即0x010000 ~ 0x10FFFF)时,Unicode码减去0x10000后正好对应成20位二进制,依次填入以下四个字节的20个空位中:
110110xx xxxxxxxx 110111xx xxxxxxxx
前两个字节称为高位WORD,以110110开头;后两个字节称为低位WORD,以110111开头。

UTF-32方案

UTF-32方案是一种定长存储方案,它总是采用4个字节存储Unicode码,由于Unicode码只有24位,于是UTF-32方案不对Unicode码做任何变化直接存储。
有人会问,用3个字节不也是可以完全存储Unicode的所有编码吗?我个人的理解是,由于Unicode的前身:通用字符集(Universal Character Set, UCS)分为了2字节编码的UCS-2和4字节编码的UCS-4。为了使编码方案统一,UCS-4承诺不再向0x10FFFF之后编码,并由UCS-2作为编号为0的plane(Basic Multilingual Plane, BMP)共同组成Unicode编码。3者之间的关系为:
UCS-4编码中0x00000000 ~ 0x0010FFFF的部分组成了Unicode编码
Unicode编码中0x000000 ~ 0x00FFFF的部分组成了UCS-2编码
因此UTF-16作为UCS-2编码的存储方案,UTF-32作为UCS-4编码的存储方案使用4个字节,还是仍然保留着。

关于字节序(Byte Order Mark, BOM)

在UTF-16和UTF-32中存在着Little endian (LE)和Big endian (BE)两种传输字节流的方式(显然很蛋疼)
为了让机器识别出这两种传输方式,在Unicode编码规范中设定了一个叫做"ZERO WIDTH NO-BREAK SPACE"的状态位0x00FEFF,它不对应任何实际含义的字符,且总是出现在文件的开头,用于标志该文件是使用什么方式读取字节流的(LE or BE)。按照上文三种存储方案的规则:

编码方案 BOM(十六进制)
UTF-8 EF BB BF
UTF-16LE FF FE
UTF-16BE FE FF
UTF-32LE FF FE 00 00
UTF-32BE 00 00 FE FF

可见由于UTF-8不存在LE或BE的区分,因此它的BOM只有一种,可有可无。所以在UTF-8的方案下,有UTF-8 BOM和UTF-8 无BOM两种,而它们的区别仅仅是文件开头有没有EF BB BF 这三个字节罢了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容