RIVALSA网络日志

Unicode与UTF-8

于2020-08-20发布

计算机中的任何数据都是通过二进制来存储的,字符也不例外。要想用二进制数字来表示字符,我们就必须要建立一个规则,将字符与二进制数一一对应,这个对应关系就称为字符集。按照这个对应关系将字符转换为的二进制称为原字符的编码

对于英文字符,通常采用ASCII字符集,用7个二进制位(占用1字节,最高位填充0b0)表示。例如空格的编码为32(二进制:0b100000,十六进制:0x20),数字5的编码为53(二进制:0b110101,十六进制:0x35),等号的编码为61(二进制:0b111101,十六进制:0x3D)等。但ASCII字符集中仅包含英文字母与部分英文符号,为了让其他语言文字也能在计算机中表示出来,就必须给它们也进行编码,由于ASCII已经占用了最高位为0b0的128个编码,所以要想只用1个字节来编码,其他语言字符就只剩最高位为0b1的128个编码可用了。但是由于各个语言都需要占用这128个编码,必然导致某个编码在不同的语言中表示的字符不同,也就会引起乱码的问题。

要想解决乱码的问题也很简单,只要让每一个字符所对应的编码都保持独一无二即可,这就是Unicode字符集。在Unicode字符集中,有些编码仅占用1个字节,有些编码占用2个字节,有些编码需要占用更多个字节。但这又带来了新的问题:由于Unicode编码所占用的字节数是不固定的,所以计算机并不知道该按照几个字节的内容来进行解码。比如:“卅”字用Unicode编码为0b101001101000101(十六进制:0x5345),占用了2个字节,但计算机在解码的时候并不知道应该解码为0x5345(中文“卅”)一个字符,还是应该解码成0x53(大写字母“S”)和0x45(大写字母“E”)两个字符。所以Unicode字符集虽然给所有的字符都对应了一个唯一的编码,但要实现起来还是存在一些问题的。

UTF-8就是Unicode编码的实现方式之一,是基于Unicode编码的一种编码。它按照如下规则进行编码(除去固定的二进制位外,所有的x组成的二进制数为对应字符的Unicode编码)。

UTF-8编码占用字节数 二进制编码 对应Unicode编码的位数
1字节 0b 0xxxxxxx 1位-7位
2字节 0b 110xxxxx 10xxxxxx 8位-11位
3字节 0b 1110xxxx 10xxxxxx 10xxxxxx 12位-16位
4字节 0b 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 17位-21位
... ... ...

如果UTF-8编码为1个字节,则直接使用对应的Unicode编码(最高位为0b0),对于此字符,UTF-8编码、Unicode编码、ASCII码是相同的;如果UTF-8编码为n(n>1)个字节,则第1个字节的高n位全为0b1,第1个字节的第高(n+1)位为0b0,除了第一个字节外的所有字节的高2位都是0b10,前面没有提到的所有二进制位全部由此字符的Unicode编码组成。

例如:“卅”字的Unicode编码为0b101001101000101(十六进制:0x5345),是由15位二进制数组成的,根据上表,其UTF-8编码需要3个字节,对应的编码为0b1110xxxx10xxxxxx10xxxxxx。在编码中的所有x用对应的Unicode编码替换,位数不足的在高位补0b0,所以“卅”字的UTF-8编码即为0b111001011000110110000101(十六进制:0xE58D85)。

“卅”字的Unicode与UTF-8编码对比

(正文完)

已获得3个赞0个差评

2条评论

Rivalsa MOD - 2020-08-20 16:18:51

@SLiMan 其实很简单,“如果UTF-8编码为n(n>1)个字节,则第1个字节的高n位全为0b1”,也就是说只要看第一个字节的高位有多少个连续的1,这个编码就是由多少个字节组成的。
后续我会略微修改文章,把这部分描述的更清楚一点。

SLiMan - 2020-08-20 14:51:26

讲的很详细,不过后面关于UTF-8如何解决Unicode不确定占用字节数还是有些没看明白

发表评论