UTF-8的编码单元是8位字节,每个码点编成1至4个字节。它的编码方式很简单,按照码点的范围,把码点的二进制位拆分成1至最多4个字节:
码点范围 | 码点位数 | 字节1 | 字节2 | 字节3 | 字节4 |
---|---|---|---|---|---|
U+0000~U+007F | 7 | 0xxxxxxx | |||
U+0080~U+07FF | 11 | 110xxxxx | 10xxxxxx | ||
U+0800~U+FFFF | 16 | 1110xxxx | 10xxxxxx | 10xxxxxx | |
U+10000~U+10FFFF | 21 | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
1000 0000 -> 80 1100 0000 -> C0 1110 0000 -> E0 1111 0000 -> F0
1111 1111 -> FF 0011 1111 -> 3F
e.g. U+20AC 0x0800 < 0x20AC < 0xFFFF 所以0x20AC有16位码点,编成三字节 0x20AC的二进制为 10 0000 1010 1100 需要16位,所以在前面补0,即 0010 0000 1010 1100 将其分成三组: 0010, 000010, 101100 加上前缀: 1110 0010, 1000 0010, 1010 1100 则得到 0xE2, 0x82, 0xAC
10 0000 1010 1100 » 12 -> 10 -> 0000 0010 0000 0010 & 1111 1111 -> 0000 0010 1110 0000 | 0000 0010 -> 1110 0010 -> 0xE2
10 0000 1010 1100 » 6 -> 1000 0010 1000 0010 & 0011 1111 -> 0000 0010 1000 0000 | 0000 0010 -> 1000 0010 -> 0x82
10 0000 1010 1100 & 00 0000 1111 1111 -> 00 0000 1010 1100 00 0000 1000 0000 | 00 0000 1010 1100 -> 1010 1100 -> 0xAC
代码表示(C):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// u <= 0x007F
PUTC(c, u & 0xFF);
// u <= 0x07FF
PUTC(c, 0xC0 | ((u >> 6) & 0xFF));
PUTC(c, 0x80 | (u & 0x3F);
// u <= 0xFFFF
PUTC(c, 0xE0 | ((u >> 12) & 0xFF));
PUTC(c, 0x80 | ((u >> 6) & 0x3F));
PUTC(c, 0x80 | (u & 0x3F));
// u <= 0x10FFFF
PUTC(c, 0xF0 | ((u >> 18) & 0xFF));
PUTC(c, 0x80 | ((u >> 12) & 0x3F));
PUTC(c, 0x80 | ((u >> 6) & 0x3F));
PUTC(c, 0x80 | (u & 0x3F));