Unicode 与 UTF-8 的本质与转换

对于大多数人来说,ASCII码,Unicode,UTF-8等等,大家都耳熟了,但可能只是大概听过但又没有仔细深入了解。很多时候一旦遇到乱码和编码之类问题的时候就会蒙,无从下手。我最近也着手在写些网络相关的代码,想更清楚了解内部的到底是什么,故上网学习了下并作记录

1.ASCII码

计算机发展初期,美国需要用通过计算机来表达26个基本拉丁字母、阿拉伯数字和英式标点符号,通过制定编码来表达它们。那既然是美国,那只需要表达英语和一些常的符号呗,反正不多,计划用1个字节(即8个bit),一个bit表达0或1,从00000000到11111111,使用7位二进制表达,最高位用作奇偶校验。
使用7位二进制数表达的内容是:

十进制范围 十六进制范围 表达的内容
0 ~ 31 (00000000 ~ 00011111) 控制字符
32 ~ 47 (00100000 ~ 00101111) 标点符号、运算符号
48 ~ 57 (01000001 ~ 00111001) 0到9十个阿拉伯数字
58 ~ 64 (00111010 ~ 01000000) 标点符号、运算符号
65 ~ 90 (00110000 ~ 01011010) 26个大写英文字母
91 ~ 96 (01011011 ~ 01100000) 标点符号、运算符号
97 ~ 122 (01100001 ~ 01111010) 26个小写英文字母
123~ 126 (01111011 ~ 01111110) 标点符号、运算符号
127 (01111111) 控制字符(DEL)

它们的排列是有规则的:

  1. 0-9<A-Z<a-z
  2. 同个字母的大写字母比小写字母要小32
  3. 同类型可比较字符呈现为递增,如0-9为递增的, A~Z为递增的

好了好了,其实这么一说,好像本质的东西都讲完了吧?就是每一个坑对应一个字符,用一个字节来表达就好了。

但是,随着计算机要发展了,很多国家逐步普及使用,各个国家有各个国家的国歌,噢不是,是各个国家有各个国家的语言,明显这一个字节是不够的啊,例如我们中国汉字博大精深多达数万个。

那么问题来了,既然这么多个国家,为了大家有个可以大家都能唯一表达一个“字”的方法,那就全世界所有国家的字都定一个唯一码,对应某个字,于是有个国际组织就搞了一套唯一码,就是我们常见的Unicode,用一个独一无二的编码来表达一个字符。

2.Unicode

Unicode,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言的要求,是一个字符集,charset。
既然是一个集合,对于计算机需要解析的时候,如果给出一串Unicode的时候,应该怎么处理好呢?
我们假设一下:
如果按最长的字符来规定所有字符都是统一长度,这样是可以解析出来,但是:汉字需要三个或四个字来达,类似像ASCII码等只需要1个字节可以表达的,这样子的话不就有两个多余的字节了吗?
对于计算机科学家来说可是不乐意了,足足浪费了那么多的字节。这个时候UTF-8就应运而生了。

3.UTF-8

既然有了唯一码,又想节省字节来表达,意味着:有些长的,有些短的,就需要用变长来处理。
那么,既然每个字节是变长的,那我要怎么制定这个编码规则呢?
UTF-8,它可以用1至4个字节对Unicode字符集中的所有有效编码点进行编码,属于Unicode标准的一部分。
UTF-8 的编码规则很简单,只有2条:
1.对於单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。
2.对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位全部设为10。其余标识为“x”的二进制位,全部为这个符号的Unicode码,Unicode码从右到左,按位置从右到左填入,不足的用0填充。

Unicode符号范围(十进制) Unicode符号范围(十六进制) Byte 1 Byte 2 Byte 3 Byte 4
0, 127 U+0000 - U+007F 0xxxxxxx
128, 2047 U+0080 - U+07FF 110xxxxx 10xxxxxx
2048, 65535 U+0800 - U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
65536, 1114111 U+10000 - U+1FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

(为了方便阅读,多显示一列10进制的范围)

4.Unicode 与 UTF-8的转换

既然有了字符集,又有编码规则,那怎么把一个Unicode转换成UTF-8编码呢?举个例子,“乐”字。

  1. 先把“乐”字的Unicode码找出来为:4E50 (Unicode编码表链接地址)
  2. 把“乐”的十六进制的Unicode转换成二进制:‭0100111001010000‬
  3. 4E50处于编码规则的第三行范围内,故把第2步转换的二进制填入,得:11100100 10111001 10010000‬
  4. 把填入规则后的二进制转换成16进制:‭E4B990‬‬
  5. 最后得出“乐”字UTF-8编码为:‭E4B990‬
    如果想把UTF-8查看它的Unicode是什么,把以上步骤反推即可。

5.小结;

对于字符集(charset)和编码规则(UTF-8等)要有清晰的区分
Unicode是一个字符集,是把所有语言的每一个字符都给了一个唯一的“id”
UTF-8是编码规则,如何通过变长规则把Unicode转换成自己的编码。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章