编码知识

摘录自http://newhtml.net/from-unicode-to-emoji/

ACII

ASCII基本上是所有程序员都能熟知的编码,这个编码本身的规则也比较简单:

  • ASCII使用一个字节来表示一个字符,一个字节一共有256种可能性,
  • 其中第0~31种可能性,用来表示各种控制符,例如换行符
  • 32~126用于表达可见字符,包括字母、数字、常用标点等
  • 第127种可能性是删除符,也属于一个控制符

在ASCII中,256种可能性只占用了128种,这128种可能性实际都位于1个字节的低7位中,最高位并没有内容。那么我们就可以在最高位做手脚,来识别一个字节究竟是ASCII,还是新编码2个字节中的第一个。
至于2个字节组合起来到底是什么字符,不同国家、地区以及公司,都有不同的安排,这个安排就是所谓的代码页了。因此,代码页不是一种编码,而是一系列编码所采用的方法。GBK这样的编码,就是在这个时代背景下诞生的。

下图是GBK编码对2个字节的使用情况,这张图来自于维基百科。


1.png

不过,代码页并没有完全解决编码问题。

首先,代码页逐渐成为了操作系统、文字软件中,语言设置的一部分,并不在文件或字符当中。这就是说,在日文操作系统下产生的含有日文文字的文件,传输到中文操作系统下打开,就会因为彼此系统的代码页不同,而无法正常显示,俗称乱码。不过这还不是最惨的。
其次,单单Windows就有一百余种代码页,IBM、HP等厂商也有自己规定的代码页。IBM大型机上甚至有一千多种代码页。这就使得代码页的自动推导,很难施行。机器无法仅仅根据内容来准确判断文件所使用的代码页。当然,这个问题在今天看来未必完全不可行,毕竟现在人人都说自己在搞机器学习。我不是这方面的专家,我和当时的程序员一样一筹莫展。

最致命的一点是,各个组织、标准、国家,无法在哪个字符如何表达上达成一致,同一个二进制序列所代表的意思,产生了很大的歧义。即使2个字节能够涵盖现今文化中的所有字符,但大家无法妥善规范,又有什么意义呢。

Unicode

Unicode是将一切字符编码到同一个编码体系的结果。
Unicode给每个字形一个独立的表示,叫做“码点”(code point)。为了方便表示,码点一般写作“U+xxxxx”,其中x为16进制表示的数字。例如U+54C8,就是“哈”。
用途或意思相近的码点被划分到不同的组当中,叫做“平面”(plane)。目前一共规定了16个平面,目前只使用到了其中少数几个。


2.png

截至Unicode 10.0,Unicode一共规定了136,690个不重复字符。

可以看出,目前我们使用到的绝大部分字符,都放在BMP当中。
这里面有一个非常眼熟的缩写:CJKV。程序员老鸟可能见过CJK,CJK是什么呢?CJK特指中国(China)、日本(Japan)、韩国(Korea)这三国的表意文字。那么CJKV是什么意思呢?我特地查了一下,原来越南曾经也使用过汉字,被称为喃字。Unicode后来也包含了喃字,因此有了CJKV这个缩写。


3.png

组合与拆分

Unicode中存在“组合字”的概念。使用者可以通过组合多个码点,“拼”出一个完整的字。

例如,Á 实际可以由U+0041(“A”)与U+0301 (“◌́” )组合而成。在不同的环境里,U+0301可能会展示成不同的样子,不过如果你的软件支持,它应该会很像是一个拼音二声的样子。
最厉害的是,这种组合拆分不一定发生在两个“半字”之间,还有可能更多个!

例如“ệ”这个越南字母,可以有多达5种组合方式:

U+1EC7 “ệ”
U+1EB9 “ẹ” + U+0302 “◌̂”
U+00EA “ê” + U+0323 “◌̣”
U+0065 “e” + U+0323 “◌̣” + U+0302 “◌̂”
U+0065 “e” + U+0302 “◌̂” + U+0323 “◌̣”

UTF一家子

上面的Unicode编码完成了给每个字符,甚至每个字形、字元一个编号的过程。但正如之前所说,编码的第二步,是还需要将这些编号能够序列化,否则这些编码只能停留于理论,无法进行传输和传播了。

不过在讲如何序列化Unicode之前,需要先稍微卖个关子,说一下字节序。

字节序是要解决一个问题:如果一次读取多个字节,组合成一个更大的数字时,哪部分在低位,哪部分在高位?

计算机世界里有两种主流字节序:大端序、小端序。大端序的意思是,先序列化的是大端,因此大端在前面传输;而小端序的意思是,先序列化的是小端,因此小端在前面传输。

例如,0x0A0B0C0D,这么长一个数字,在大端序和小端序的样子就是:

大端序:0A 0B 0C 0D
小端序:0D 0C 0B 0A

因为Unicode要使用不止一个字节来表示一个字符,字节序就成为了序列化时一个重要的考量点。

UTF-32

尽管UTF-8是大家最熟悉的Unicode序列化格式,但我想先说说UTF-32,这个编码是最为简单的。

UTF-32每个字符固定使用4个字节,因此理论上最多表达2564种字符。然而实际上UFT-32要求每个字符最高位必须为0,所以比2564稍微要少一些,不过仍然足以覆盖Unicode。

那么字节序怎么去考虑呢?

如果一个文件使用UTF-32存储,通常需要以U+FEFF来开头。如果程序读出的是0x00 0x00 0xFE 0xFF,则表示文件内容是小端序,反之则说明是大端序(0xFF 0xFE 0x00 0x00)。

这个特殊的四字节,被称为BOM。

UTF-16

UTF-16就比UTF-32要复杂一些了,不过大体上来说,除了构成“代理编码对”(surrogate pair)的情况以外,每个字符使用2个字节存储。而且和你想的一样,UTF-16也需要BOM,只不过BOM缩减到了2个字节。
那么什么是“代理编码对”呢?

最早UTF-16可以像UTF-32一样简单,只计划包含6万多个码点。令人意外的是,Unicode后来超过了这个数量,于是就有了代理编码对这样的技巧。

原理上来说,就是将一部分字符的表达,拆成了4个字节来表示。而为了不造成混淆,之前一些有效的2字节组合,也不再对应真实字符。

因此UTF-16的解码和编码,并不是简单地查表翻译,而存在一个“if”的情况。具体的算法并不复杂,大家可以自己搜索一下如何实现。维基百科上有一个非常不错的例子。

UTF-8

UTF-8可能是最常用的Unicode传输格式了,别看名字上是“8”,但实际只有ASCII涵盖的那些字符,才是真正1个字节。而Unicode里的其他字符,可能占用2个字节,也可能占用3个甚至4个字节。

UTF-8的算法比较精巧,在算法执行过程中,需要根据特定的情况来决定一个字符是否已经读完。而且算法当中也已经囊括了字节序相关的信息,因此UTF-8并不需要BOM。

由于兼容ASCII,UTF-8对于以英文为主的文本,最节省存储空间。这里特别注意下,UTF-16和UTF-32是不兼容ASCII的哦。

UTF-7

下面来说说这个异类。早期一些软件及协议对字符的限制很严格,导致使用了最高位的UTF-8在这些软件或协议中就会出现问题。UTF-7就是只使用低7位来进行编码。

具体的编码规则在这就不赘述了,我自己也没有深入去看,大体上来说,就是将一部分合法的ASCII字符用作转义,类似于base64。

不过值得一提的是,由于UTF-7中的转义规则,一些ASCII字符也可以被转义。例如“<”和“>”可以被转义为“+ADw-”“+AD4-”。这曾经导致过一些网站遭受UTF-7 XSS攻击,攻击者利用UTF-7编码逃过了敏感字符过滤,进而大摇大摆地向页面注入了自己的JS代码。关于这一点,感兴趣的各位可以自己搜索一下。

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

推荐阅读更多精彩内容

  • 0 前言 在平时的开发过程中大部分人应该都遇到过中文乱码问题,浏览网页时也会遇到内容显示乱码的情况,一般遇到这种情...
    小猪啊呜阅读 2,580评论 1 10
  • 字符是用户可以读写的最小单位。计算机所能支持的字符组成的集合,就叫做字符集。字符集通常以二维表的形式存在。二维表的...
    刘惜有阅读 8,117评论 2 14
  • 前言 很多程序员对字符编码不太理解,当然平时接触的也不是很多。可能只是大概知道 ASCII、UTF8、GBK、Un...
    ZhengYaWei阅读 1,405评论 0 7
  • 翻过一层读,方能见其真意 过片“高楼谁与上”,按字意说,是问“我还能与谁再等上高楼呢”?这句话有一个词序倒置,正常...
    空中语阅读 571评论 0 1
  • 焦点网络九期中级紫分享第215天 当发生一件事,孩子们就会有思考结论,有感受,做出相应行为。他她们的结论会有偏激,...
    紫smile阅读 128评论 0 0