有你在真好 的个人博客
怎么理解Unicode
阅读:2186 添加日期:2021/3/27 23:30:34 原文链接:https://www.toutiao.com/item/6196536269277004289/

SCII、UTF8、UTF16、UTF32、Unicode、GBK,在我们遇到编码问题时,这些词总能在我们响起。作为一个程序员,我们迟早也会遇到所谓的“编码”问题,在UTF8现在如此普及的情况下,可能我们写程序也不用太考虑这些东西,不过,你是否对这些问题总感觉有点似懂非懂理不清呢?下面,跟大家一起讨论一下Unicode,理解了它,我想再理解其它编码,也不是什么难事了。

“编码”这个词,总是有点让人模棱两可,我们常说UTF8编码,ASCII码,Unicode编码,GBK编码,或ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。这些术语也是容易让我们糊涂的,我们先不纠结这些术语,下面直接讨论讨论Unicode。

UCS(Universal Character Set,通用字符集)或者说Unicode字符集,我们就当他们是一回事吧——就是某个权威机构规定的一个字符集,这里要包含世界上所有的字符。为了区分一个不同字符,他们给每一个字符分配一个码位(Code Point),所谓的码位,其它就是一个整数(这里我们刻意不用“编码”这个词)。为了存储这个整数(码位),我们又需要一些规范,比如,UTF8,UTF16,UTF16LE,UTF16BE,UTF32,UTF32LE,UTF32BE就是规范这个整数如何存储的,我们可以称这些为“编码”,但一定得跟Code Point区分开来。

Unicode字符集的码位区间从0x00至0x10FFFF(用U+00到U+10FFFF表示),最大的数0x10FFFF表示成二进制需要21位,也就是说,UTF8,UTF16,UTF16LE,UTF16BE,UTF32,UTF32LE,UTF32BE要做的就是如何存储一个最长21位的二进制数。

怎么理解Unicode

UTF8——上面的图是UTF-8存储形式,码位小于0x7F占一个字节,可以兼容ASCII码,汉字的对应的码位,落在0x800-0xFFFF中,所以占三个字节。UTF8最多占四个字节,上图中四字节的UTF8,可用的位数(X的数量)正好也是21,所以所有的Unicode码位都能放下。

UTF16——我们平时称的UTF16其实是UTF16LE,与之对应的是UTF16BE,就是小端和端端的概念。小于0x10000的码位,可以用两个字节来表示,比如码位U+0AFF,可以用两个字节来表示,0x0A和0xFF,如果是小端,最终存储形式为"\xFF\x0A",如果是大端,存储形式为"\x0A\xFF"。对于大于0x10000的码位,显然两个字节存不下了,以码位中最大的U+10FFFF为例,上面我们说过表示需要21位。我们把0x10FFFF减掉0x10000等于0xFFFFF,0xFFFFF需要用20位来表示,把这20位分成高10位(0x3FF)和低10位(0x3FF),高10位加0xD800得到一个16bit的数(0xDBFF),低10位加0xDC00得到另一个16bit的数(0xDFFF),小端模式下,组合得到"\xFF\xDB\xFF\xDF",大端模式下得到"\xDB\xFF\xDF\xFF",这分别是U+10FFFF这个码位对应的UTF16LE和UTF16EB编码。所以,虽然叫UTF16,但是并不是都是用两字节来表示哦,还有可能是四个字节。

UTF32——跟UTF16类似,不同的是,直接用四个字节存储,足够放下最大21位的码位。

我们平时称的Unicode编码,如果特指一种,可以理解成是指UTF16LE,或者也可理解是UTF8、UTF16等这些编码的合集,看你要怎么去理解了。然后这些编码之间的相互转化,用码位做中转就行了。

UTF8编码转码位比较简单些,跟据上图,根据高位字节1个数可以判断需要后续几个字符来组合。UTF16编码转码位可能会让我们疑惑,初看上面的算法,我们知道U+0000到U+FFFF,都是合法的码位,我们每次读取的两字节,一定对应一个合法的码位,那什么情况下,我们难知道一个码位是由四字节组成的呢?开始我也很疑惑,不过如果大家去看看Unicode的码位表就或以知道答案了,如下图所示,D800-DBFF和DC00-DFFF的码位本身就是有特殊函义的,而我们上面从码位转UTF16时的算法,计算的两个值刚好只可能落在这两个区间。所以我们每次取两个字节,如果第一字节落在D800-DBFF间,则需要再取出后两个字节,然后再把码位转UTF-16的算法逆转一下。

怎么理解Unicode

ICP备案号:苏ICP备14035786号-1 苏公网安备 32050502001014号