UTF-8究竟是怎么编码的

1.

UTF-8编码是Unicode字符集的一种字符编码方式(CEF),其特点是使用变长字节数(即变长码元序列或称变宽码元序列)来编码。目前一般是1到4个字节,当然,也可以更长。

为什么要变长呢?这可以理解为按需分配,比如一个字节足以容纳所有的ASCII字符,那何必补一堆0,导致占用更多的字节来存储呢?

实际上变长编码有其优势,也有其劣势,优势方面除了上面所讲的节省存储空间之外,还有就是自动纠错性能好、利于传输、扩展性强,而劣势方面主要是由于字符的编码字节数不固定导致不利于程序内部处理,比如导致正则表达式检索的复杂度大为增加;而UTF-32这样的等长码元序列(即等宽码元序列)的编码方式就比较适合程序处理,当然,缺点是比较耗费存储空间。

2.

那UTF-8究竟是怎么编码的呢?也就是说其编码算法是什么?

UTF-8编码最短的为一个字节、最长的目前为四个字节,从首字节就可以判断一个UTF-8编码有几个字节:

  • 如果首字节以0开头,肯定是单字节编码(即单个单字节码元);
  • 如果首字节以110开头,肯定是双字节编码(即由两个单字节码元所组成的双码元序列);
  • 如果首字节以1110开头,肯定是三字节编码(即由三个单字节码元所组成的三码元序列),以此类推。

另外,UTF-8编码中,除了单字节编码外,由多个单字节码元所组成的多字节编码其首字节以外的后续字节均以10开头(以区别于单字节编码以及多字节编码的首字节)。

0、110、1110以及10相当于UTF-8编码中各个字节的前缀,因此称之为前缀码。其中,前缀码110、1110及10中的0,是前缀码中的终结标志。

UTF-8编码中的前缀码起到了很好的区分和标识的作用:

  • 当解码程序读取到一个字节的首位为0,表示这是一个单字节编码的ASCII字符;
  • 当读取到一个字节的首位为1,表示这是一个非ASCII字符的多字节编码字符中的某个字节(可能是首字节,也可能是后续字节),接下来若继续读取到一个1,则确定为首字节,再继续读取直到遇见终结标志0为止,读取了几个1,就表示该字符为几个字节的编码;
  • 当读取到一个字节的首位为1,紧接着读取到一个终结标志0,则该字节显然是非ASCII字符的后续字节(即非首字节)。

(笨笨阿林原创文章,转载请注明出处)

3.

所以,1~4字节的UTF-8编码看起来分别是这样的:

单字节可编码的Unicode码点值范围十六进制为0x0000 ~ 0x007F,十进制为0 ~ 127;

双字节可编码的Unicode码点值范围十六进制为0x0080 ~ 0x07FF,十进制为128 ~ 2047;

三字节可编码的Unicode码点值范围十六进制为0x0800 ~ 0xFFFF,十进制为2048 ~ 65535;

四字节可编码的Unicode码点值范围十六进制为0x10000 ~ 0x1FFFFF,十进制为65536 ~ 2097151(目前Unicode字符集码点编号的最大值为0x10FFFF,实际尚未编号到0x1FFFFF;这说明作为变长字节数的UTF-8编码其未来扩展性非常强,即便目前的四字节编码也还有大量编码空间未被使用,更不论还可扩展为五字节、六字节……)。

(笨笨阿林原创文章,转载请注明出处)

4.

上述Unicode码点值范围中十进制值127、2047、65535、2097151这几个临界值是怎么来的呢?

因为UTF-8编码中的每个字节中都含有起到区分和标识之用的前缀码0、110、1110以及10之一,所以1~4个字节的UTF-8编码其实际有效位数分别为8-1=7位(2^7-1=127)、16-5=11位(2^11-1=2047)、24-8=16位(2^16-1=65535)、32-11=21位(2^21-1=2097151),如下表所示:

注:上图中的Unicode range为Unicode码点值范围(也就是Unicode码点编号范围),Hex为16进制,Binary为二进制;Encoded bytes为UTF-8编码中各字节的编码方式(即编码算法),其中,x代表Unicode二进制码点值的单字节或低字节中的低7位或8位、y代表两字节码点值的高字节中的低3位或8位以及三字节码点值的中字节中的8位、z代表三字节码点值的高字节中的低5位。

因此,UTF-8编码的算法简单地来概括就是:首先确定UTF-8编码中各个字节的前缀码;之后再将UTF-8编码中各个字节除了前缀码所占用之外的位,依次分配给Unicode字符码点值二进制中各个位的值。换言之,就是用Unicode字符码点值二进制中各个位的值,依次填充UTF-8编码中的各个字节除了前缀码所占用之外的位。

5.

由于ASCII字符的UTF-8编码使用单字节,而且和ASCII编码一模一样,这样所有原先使用ASCII编码的文档就可以直接解码了,无需进行任何转换,实现了完全兼容。考虑到计算机世界里的英文文档数量之多,这一点意义重大。

而对于其他非ASCII字符,则使用2~4个字节的编码来表示。其中,首字节中前置的“1”的个数代表该字符编码的字节数(如110代表两个字节、1110代表三个字节,以此类推),非首字节之外的剩余后续字节的前两位始终是10,这样就不会与ASCII字符编码(“0”开头)以及非ASCII字符的首字节编码(110或1110等至少两个“1”开头)相冲突。

例如,假设某个字符的首字节是1110yyyy,前置有三个1,说明该字符编码总共有三个字节,必须和后面两个以10开头的字节结合才能正确解码该字符。

6.

由此可知,UTF-8编码设计得非常精巧,虽说不上完美无瑕,但若与后文将要介绍的UTF-16、UTF-32以及前文介绍过的那些ANSI编码相比较,对于其精巧设计将体会得更为深切透彻。因此,UTF-8越来越得到全球一致认可,大有一统字符编码之势

(笨笨阿林原创文章,转载请注明出处)

(未完待续)

预告:本系列文章下一篇将重点介绍UTF-16编码,敬请关注!】

【转】刨根究底字符编码之十二——UTF-8究竟是怎么编码的相关推荐

  1. 【转】刨根究底字符编码之十六——Windows记事本的诡异怪事:微软为什么跟联通有仇?

    1. 当用一个软件(比如Windows记事本或Notepad++)打开一个文本文件时,它要做的第一件事是确定这个文本文件究竟是使用哪种编码方式保存的,以便于该软件对其正确解码,否则将显示为乱码. 一般 ...

  2. 【转】刨根究底字符编码之十——Unicode字符集的字符编码方式

    一.字符编码方式CEF的选择 1. 由于Unicode字符集非常大(并且作为开放字符集还在不断扩展之中),有些字符的编号(即码点值)需要两个或两个以上字节来表示,而要对这样的编号进行编码,也必须使用两 ...

  3. 【转】刨根究底字符编码之二——关键术语解释(下)

    关键术语解释(下) 如前所述,现代字符编码模型共分为5层,下面分层进行简要介绍. 一.第1层 抽象字符表ACR (Abstract Character Repertoire抽象字符清单):明确字符的范 ...

  4. C语言学习(十二)C语言中的字符(宽字符与窄字符)、从字符谈谈C语言的编码、转义字符

    C语言学习(十二)C语言中的字符(宽字符与窄字符).从字符谈谈C语言的编码.转义字符 目录 C语言学习(十二)C语言中的字符(宽字符与窄字符).从字符谈谈C语言的编码.转义字符 英文字符 字符的表示 ...

  5. (十二)Core Java IO流(Properties,序列化,管道流,字符编码)-03 (108)

     目录 :             41 ). IO流(创建java文件列表) 42 ). IO流(Properties简述) 43 ). IO流(Properties存取) 44 ). IO流(Pr ...

  6. python基础(十二):字符字节编码解码

    基础(十二) 字符串概述 类型 编码架构 字符串存储 常用字符编码 ASCII latin-1 UTF-8(通用性更好) UTF-16 UTF-32 内置函数 ord() chr() str.enco ...

  7. 【转】刨根究底字符编码之十四——UTF-16究竟是怎么编码的

    1. 首先要注意的是,代理Surrogate是专属于UTF-16编码方式的一种机制,UTF-8和UTF-32是不用代理的. 如前文所述,为了让UTF-16能继续编码基本平面后面的增补平面中的码点值,于 ...

  8. 刨根究底字符编码之十四——UTF-16究竟是怎么编码的(“代理区(Surrogate Zone)”,范围为0xD800~0xDFFF(十进制55296~57343),共2048个码点未定义。UTF8和

    1. 首先要注意的是,代理Surrogate是专属于UTF-16编码方式的一种机制,UTF-8和UTF-32是不用代理的. 如前文所述,为了让UTF-16能继续编码基本平面后面的增补平面中的码点值,于 ...

  9. 【转】刨根究底字符编码之十一——UTF-8编码方式与字节序标记BOM

    一.UTF-8编码方式 1. 接下来将分别介绍Unicode字符集的三种编码方式:UTF-8.UTF-16.UTF-32.这里先介绍应用最为广泛的UTF-8. 为满足基于ASCII.面向字节的字符处理 ...

最新文章

  1. python广告搞笑_技术入门 | 听说Python的广告刷爆了你的朋友圈?
  2. c++ 出现1.#IND、1.#INF
  3. 第六章 深度学习(中下)
  4. 性能测试初学_windows 计数器
  5. 为某人命名以重新连接到您的服务器
  6. java的编辑框丢失焦点_java – 捕获EditText丢失焦点
  7. 1.4编程基础之逻辑表达式与条件分支 03 奇偶数判断
  8. 1075 - Incorrect table definition;there can be only one auto column and it must be defined as a key
  9. SpringBoot 解决“不支持发行版本xx”的问题
  10. C# 值类型和引用类型
  11. 软件we端压力测试,软件压力测试报告
  12. android 图片尺寸修改工具,图片尺寸修改器手机版下载_图片尺寸修改器安卓下载v 6.3...
  13. 登录注册判断+Mysql
  14. win 10iis php7,win10下设置IIS、安装php7.2
  15. 有运气摇号来不及挑选?网易有数帮你科学选房
  16. php捕捉Warning、Notice错误
  17. 爬虫项目:scrapy爬取昵图网全站图片
  18. 给定两个有着相同长度且都在字典内的单词,要求写一个方法来把一个单词变型成另一个单词。 一次只能转换一个字母,且每次生成的单词必须在字典内...
  19. NUC977 烧录uboot到 SPI flash
  20. 下载iCloud照片/文件的正确姿势(亲测好使)

热门文章

  1. matlab绘制三维图形
  2. 腾讯后台开发面试总结,原创,吐血推荐!!
  3. Python学习 Day 3 字符串 编码 list tuple 循环 dict set
  4. UDP模式与TCP模式的区别
  5. 关于规划修编标准的问题
  6. 从决策树到xgboost(一)
  7. 什么是word2vector
  8. HDU 5882 Balanced Game 分析+欧拉图
  9. 休眠后gpio状态_1.Linux电源管理-休眠与唤醒
  10. 1189C. Candies