字符编码1——Unicode 编码与UTF-8、UTF-16

1.什么是Unicode?

unicode官网的简介

The Unicode Standard provides a unique number for every character, 
no matter what platform, device, application or language. 

Unicode给每一个符号都给予一个独一无二的编码。

2.Unicode问题

阮一峰 字符编码笔记:ASCII,Unicode 和 UTF-8有清晰的介绍:
Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

这里就有两个问题:

  • 第一个问题是,如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?
  • 第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果 Unicode 统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

3.Unicode 的多种存储方式(表示方式)

官网的UTF-8, UTF-16, UTF-32 & BOM介绍

there are several possible representations of Unicode data, including 
UTF-8,  UTF-16 and UTF-32. In addition, there are compression 
transformations such as the one described in the UTS #6: A 
Standard Compression Scheme for Unicode (SCSU).

什么是UTF?

A Unicode transformation format (UTF) is an algorithmic mapping 
from every Unicode code point (except surrogate code points) to a 
unique byte sequence. The ISO/IEC 10646 standard uses the term 
“UCS transformation format” for UTF; the two terms are merely 
synonyms for the same concept.

Each UTF is reversible, thus every UTF supports *lossless round 
tripping*: mapping from any Unicode coded character sequence S to 
a sequence of bytes and back will produce S again. To ensure round 
tripping, a UTF mapping *must* map all code points (except 
surrogate code points) to unique byte sequences. This includes 
reserved (unassigned) code points and the 66 noncharacters
 (including U+FFFE and U+FFFF).

The  SCSU  compression method, even though it is reversible, is not 
a UTF because the same string can map to very many different byte 
sequences, depending on the particular SCSU compressor.

UTF是将每个Unicode码点转换成唯一字节序列的映射算法。ISO/IEC 10646 标准定义UTF为“UCS transformation format” 。

每个UTF都是可逆的。UTF映射必须将所有码点映射到唯一字节序列,包括保留码点(未分配)和66个非字符(包括U+FFFE和U+FFFF)。

3.1 UTF-8

UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8 的编码规则很简单,只有二条:

  • 1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
  • 2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

参见Section 3.9, Unicode Encoding Forms


另外参考RFC3629一张图:

阮一峰 字符编码笔记:ASCII,Unicode 和 UTF-8介绍的一个示例:
严的 Unicode 是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此严的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,严的 UTF-8 编码是11100100 10111000 10100101,转换成十六进制就是E4B8A5。

3.2 UTF-16

参考彻底弄懂 Unicode 编码以及《Java核心技术 卷一》。

3.2.1 级别plane

分区定义。每个区可以存放 65536 个(2^16)字符,称为一个plane。

总共17个编码级别:

  • 最前面的 65536 个字符位,称为基本级别(简称 BMP ),它的码点范围是从 0 到 2^16-1,写成 16 进制就是从 U+0000 到 U+FFFF。所有最常见的字符都放在这个级别,这是 Unicode 最先定义和公布的一个级别。
  • 剩下的16个级别:字符都放在辅助级别(简称 SMP ),码点范围从 U+010000 到 U+10FFFF。

3.2.2 UTF-16编码规则

  • 基本级别(U+0000 到 U+FFFF)的字符占用 2 个字节
  • 辅助级别(U+010000 到 U+10FFFF)的字符占用 4 个字节

3.2.3 遇到两个字节时怎么区分是基本级别还是辅助级别?

在基本级别内,从 U+D800 到 U+DFFF 是一个空段,即这些码点不对应任何字符。因此,这个空段可以用来映射辅助级别的字符。

  • U+010000 到 U+10FFFF总共可以表示2^20个不同字符,因此这些字符至少需要20个二进制位。
  • UTF-16 将这 20 个二进制位分成两半,前 10 位映射在 U+D800 到 U+DBFF,称为高位(H),后 10 位映射在 U+DC00 到 U+DFFF,称为低位(L)。这意味着,一个辅助级别的字符,被拆成两个基本级别的字符表示。

因此,当我们遇到两个字节,发现它的码点在 U+D800 到 U+DBFF 之间,就可以断定,紧跟在后面的两个字节的码点,应该在 U+DC00 到 U+DFFF 之间,这四个字节必须放在一起解读。

3.2.4 示例

汉字"𠮷"的 Unicode 码点为 0x20BB7,该码点显然超出了基本平面的范围(0x0000 - 0xFFFF),因此需要使用四个字节表示。

  • 首先用 0x20BB7 - 0x10000 计算出超出的部分
  • 然后将其用 20 个二进制位表示(不足前面补 0 ),结果为0001000010 1110110111。
  • 接着,将前 10 位映射到 U+D800 到 U+DBFF 之间,后 10 位映射到 U+DC00 到 U+DFFF 即可。U+D800 对应的二进制数为 1101100000000000,直接填充后面的 10 个二进制位即可,得到 1101100001000010,转成 16 进制数则为 0xD842。同理可得,低位为 0xDFB7。因此得出汉字"𠮷"的 UTF-16 编码为 0xD842 0xDFB7。

4. BE, LE and unmarked

官网的UTF-8, UTF-16, UTF-32 & BOM介绍

UTF-16 and UTF-32 use code units that are two and four bytes long 
respectively. For these UTFs, there are three sub-flavors: BE, LE and 
unmarked. The BE form uses big-endian byte serialization (most 
significant byte first), the LE form uses little-endian byte serialization 
(least significant byte first) and the unmarked form uses big-endian 
byte serialization by default, but may include a byte order mark at the 
beginning to indicate the actual byte serialization used.
  • BE—— big-endian 高位在前 字节序列
  • LE——little-endian低位在前 字节序列
  • unmarked form——默认是BE方式,但是可能在最开始处有一个字节序列标记用来标识实际使用的是哪种顺序。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容