一、字符编码方式CEF的选择

1.

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

比如,汉字“严”的Unicode编号以十六进制数表示为4E25,转换成二进制数有15位(100 1110 0010 0101),对“严”这个字符的编号进行编码的话,至少需要2个字节。表示其他更大编号的字符,可能需要3个字节或者4个字节,甚至更多。

2.

这带来两个问题:

一是,如何才能区别Unicode字符和ASCII字符的编码?计算机怎么知道三个字节表示的是一个字符,而不是分别表示三个字符呢?

二是,我们知道,英文字母只用一个字节来编码就够了,而如果Unicode统一硬性规定,每个字符都用两个、三个或四个字节来编码,那么每个英文字母编码的前面都必然有一个、两个到三个字节全是0,这对于存储和传输来说是极大的浪费。

这就涉及到了字符编码方式CEF的选择问题。Unicode字符的编码方式目前最常用的是这三种:UTF-8、UTF-16、UTF-32。在具体介绍这些编码方式之前,需要再次深入了解两个概念——码点(Code Point)与码元(Code Unit)。

二、码点

1.

一个字符集一般可以用一张或多张由多个行和多个列所构成的二维表来表示。

二维表中行与列相交的点,称之为码点(Code Point代码点),也称之为码位(Code position代码位);每个码点分配一个唯一的编号,称之为码点值或码点编号,除开某些特殊区域(比如代理区、专用区)的非字符码点和保留码点,每个码点唯一对应于一个字符。

因此,除开非字符码点和保留码点,码点值(即码点编号)通常来说就是其所对应的字符的编号,所以码点值有时也可以直接称之为字符编号,虽然不够准确,但更为直接。

2.

字符集中所有码点数量的总和,称之为编号空间(Code Space,又被称之为代码空间、编码空间、码点空间、码空间)。

码点值最初用两个字节的十六进制数字表示,比如字母A的Unicode码点值为0041,常写作U+0041,这种形式称为Unicode码点名称,不严格地来讲,也可称之Unicode字符名称(因为存在着非字符码点和保留码点,并非每个码点都分配了字符,所以这种称呼不够准确,不过目前更为普遍)。

3.

后来随着Unicode字符集的不断增补扩大(比如现在的Unicode字符集至少需要21位才能全部表示),码点值也扩展为用三个字节或以上的十六进制数字表示。

例如,ASCII字符集用0~127这连续的128个数字编号分别表示128个字符。GBK字符集使用区位码的方式为每个字符编号,首先定义一个94×94的矩阵,行称为“区”,列称为“位”,然后将所有国标汉字放入矩阵当中,这样每个汉字就可以用唯一的“区位”码来标识了。例如“中”字被放到54区第48位,因此其区位码(字符编号)就是5448。

而目前Unicode标准中,将字符按照一定的类别划分到0~16这17个平面(Plane层面)中,每个平面中拥有2^16 = 65536个码点,因此,目前Unicode字符集所拥有的码点总数,也就是Unicode的编号空间为17*65536=1114112。

注意,网络上的很多文章中,代码点、码点、码点值、码值、代码位、码位、字符码、Unicode码、字符编号、字符编码、编码方案、编码方式、编码格式等等概念经常互相代替混用,让人困惑。

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

三、码元

1.

在计算机存储和网络传输时,码点值(即字符编号)被映射到一个或多个码元(Code Unit代码单元、编码单元)

码元可理解为字符编码方式CEF(Character Encoding Form)对码点值进行编码处理时作为一个整体来看待的最小基本单元(或称为最小基本单位)

2.

为什么非要引入“码元”这个概念?或者说,为什么非要强调“码元”这个概念?

码元某种程度上可认为对应于高级语言中的基本数据类型。而高级语言层面的基本数据类型,若要更深入一步地来讲,实质上对应于机器硬件层面(如汇编语言层面)的数据类型byte字节、word字、dword双字等在硬件中的表达与处理机制。

之所以要强调“码元”的概念,是因为字符编码作为一串数字序列,最终还是得通过机器硬件层面的数据类型来表示。

而码元的实质,就是机器硬件层面的数据类型;不同的码元,代表着不同位数的数据类型。当字符编码方案设计人员基于某种考虑(如时间复杂度、空间复杂度等)为某种字符编码方式CEF选择了某种码元时,其实质就是选择了某个位数的数据类型。

数据类型,在机器硬件层面上来看,只有作为一个整体来处理的二进制数字位数上的不同(如byte字节、word字、dword双字等汇编语言的数据类型,都是二进制数字值,只是位数不同而已),而并没有高级语言层面上的数值、布尔、字符等语义的不同,毕竟本质上来讲计算机只“认识”由0和1组成的数字。

正因为如此,字符编码方案设计人员在设计字符编码方式CEF时,必然要选择一种机器硬件层面上某个位数的数据类型(如byte字节、word字、dword双字等)来表示,不是选择这个位数的数据类型,就是选择那个位数的数据类型。当然这种选择会基于各种考虑,比如时间复杂度、空间复杂度等,不过一旦选择了某种数据类型,其所选择的数据类型位数上的不同,同时也就体现为了码元位数上的不同。

所以,不同位数的码元,实质上是机器硬件层面上不同位数的数据类型。(而机器硬件层面上为什么要设计不同位数的多种数据类型出来,这是另一个话题了,有兴趣可参看有关硬件方面的专著。)

3.

由于数据类型有单字节与多字节之分,所以码元也有单字节与多字节之分;而多字节数据类型由于历史的原因,存在着字节序的大端序(Big-Endian)与小端序(Little-Endian)之分,因此多字节码元也存在着大端序与小端序之分(具体详见前文中有关字节序的解释;注意,单字节数据类型是没有字节序的问题的,所以单字节码元也就没有字节序问题)。

这就是之所以要强调“码元”这个概念的关键原因。

4.

对字符编号(即字符码点值)进行编码的具体实现方式——字符编码方式CEF,就是由一个或多个码元这样的最小基本单元构成的。

最常用的码元是8位(即1字节)的单字节码元,另外还有16位(即2字节)和32位(即4字节)两种多字节码元,分别相当于汇编语言中的byte字节、word字、dword双字,以及C++中的无符号整型BYTE、WORD、DWORD。

(注: 在VC++6.0中,这三种数据类型的定义分别为:

   typedef unsigned char BYTE; // 1个字节

   typedef unsigned short WORD; // 2个字节

   typedef unsigned long DWORD; // 4个字节)

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

5.

于是,三种码元对应就有了Unicode字符编号的三种UTF编码方式(即Unicode码转换格式Unicode Transformation Format,或称通用字符集转换格式UCS Transformation Format):

   UTF-8,即8-bit Unicode/UCS Transformation Format;

   UTF-16,即16-bit Unicode/UCS Transformation Format;

   UTF-32,即32-bit Unicode/UCS Transformation Format。

或者反过来说,Unicode字符编号的三种UTF编码方式(UTF-8、UTF-16、UTF-32)分别采用了不同的码元(单字节、双字节、四字节)来编码。

例如,“汉字”这两个中文字符的Unicode字符编号是0x6C49和0x5B57,其三种UTF编码在VC++6.0中可按如下定义进行“模拟”:

6.

注意,这里之所以说是“模拟”,其中的一个重要原因,如前文所述,从本质上来讲机器硬件层面上的所有数据类型,只存在着被视作一个整体来处理的比特序列(即二进制序列)的位数不同之分,不存在着高级语言层面上数据类型的数值、字符串、布尔值等的语义不同之分。

因此,机器硬件层面上的数据类型与高级语言层面上的数据类型,严格来讲,在含义上还是有着很大不同的。当然,高级语言层面上的数据类型最终还是会被转化为机器硬件层面上的数据类型,毕竟计算机只“认识”由0和1所组成的比特流。(可同时参见前文中有关字节序的解释)

7.

这里用BYTE、WORD、DWORD分别表示无符号8位整数、无符号16位整数和无符号32位整数;因而UTF-8、UTF-16、UTF-32可认为分别以BYTE、WORD、DWORD作为码元。

“汉字”这两个中文字符的UTF-8编码需要六个BYTE(共6个单字节码元),大小是6个字节;UTF-16编码需要两个WORD(共2个双字节码元),大小是4个字节;UTF-32编码需要两个DWORD(共2个四字节码元),大小是8个字节。

由于多字节数据类型的数据在计算机存取时存在一个字节序的问题,因此,UTF-16、UTF-32这两种编码方式所编码出来的逻辑意义上的多字节码元序列,在映射为物理意义上的字节序列时,字节序列的字节序因系统平台的不同而不同。

前面已经多次强调过了,这里再次特别强调一下:由单字节数据类型所组成的多字节数据是不存在字节序的问题的。因此,采用单字节码元进行编码的UTF-8编码,虽然ASCII字符为单字节编码,而非ASCII字符却是多字节编码的,但却并不存在字节序问题,这是跟同样为多字节编码、但却采用多字节码元的UTF-16、UTF-32编码的不同之处。详见下表所列。

     Unicode字符集三大编码方式(UTF-8、UTF-16、UTF-32)比较一览表

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

【预告:下一篇将重点讲解UTF-8编码方式与字节序标记(BOM),敬请关注!

上一篇:刨根究底字符编码之九--字符编码方案的演变与字节序 - 知乎专栏

下一篇:刨根究底字符编码之十一--UTF-8编码方式与字节序标记BOM - 知乎专栏

汉字字符集编码查询_刨根究底字符编码之十——Unicode字符集的字符编码方式...相关推荐

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

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

  2. 邓白氏编码查询_外贸人常用查询工具汇总

    外贸工具类网站 FOB价格计算器 http://bbs.fobshanghai.com/fobprice.htm CIF价格计算器 http://www.easiertrade.com/public/ ...

  3. 国家职业标准职业编码查询_如何以自由职业者的身份学习编码和赚钱

    国家职业标准职业编码查询 One of the most popular and wanted jobs today is to be a coder. We've all seen photos o ...

  4. 国家职业标准职业编码查询_为什么我学会编码而不是从事金融职业

    国家职业标准职业编码查询 by Amir Ghafouri 通过阿米尔·加富里(Amir Ghafouri) 为什么我学会编码而不是从事金融职业 (Why I learned to code inst ...

  5. 课程编码查询_付出还是不付出:生活中最好的事情(例如编码课程)是否免费?...

    课程编码查询 by Rick West 由里克·韦斯特(Rick West) 付出还是不付出:生活中最好的事情(例如编码课程)是否免费? (To pay or not to pay: are the ...

  6. lv官网编码查询_想知道海关统计数据吗?这里有详细的查询教程

    海关统计数据在线查询系统优化升级了,系统更好用啦! 打开方式 1.进入海关总署官网www.customs.gov.cn,点击导航栏中的"信息公开". 2.点击左侧导航栏中的&quo ...

  7. java中编码问题_[干货预警]一次搞懂Java中的编码问题

    编码问题一直是一个困扰程序员的问题,尤其是对于java程序员.因为java的跨平台特性,经常需要在多个编码之间进行转换. 下面详细讲一讲java中的编码问题 一.为什么要编码 长话短说,原因如下: 1 ...

  8. c++ unicode转换中文_彻底弄懂UTF-8、Unicode、宽字符、locale

    结论 宽字符类型wchar_t locale 为什么需要宽字符类型 多字节字符串和宽字符串相互转换 最近使用到了wchar_t类型,所以准备详细探究下,没想到水还挺深,网上的资料大多都是复制粘贴,只有 ...

  9. 面试题字符集和编码区别_您和理想工作之间的一件事-编码面试!

    面试题字符集和编码区别 A recruiter calls you for a position with your dream company. You get extremely excited ...

  10. lv官网编码查询_【干货】商品条码(条形码)哪里查?官方查询网站和APP推荐给你~...

    就像每个人都有身份证 每个商品也有它专属的身份证明 ↓↓↓ 商 品 条 码 又称全球贸易项目代码 是指包含厂商识别代码在内的对零售商品.非零售商品.物流单元.位置.资产及服务进行全球惟一标识的一种代码 ...

最新文章

  1. Java程序员从笨鸟到菜鸟之(八十一)细谈Spring(十)深入源码分析Spring之HibernateTemplate 和HibernateDaoSupport
  2. Array with Odd Sum CodeForces - 1296A
  3. 互联网晚报 | 3月22日 星期二 |​ ​工作人员标注mu5735残骸并展开调查;万门大学疑似解散VIP群跑路...
  4. 类型转换和操作符重载 (c#)
  5. 路由器性能测试工具_小米路由器AX3600与AX1800 MESH 实测
  6. vSphere 7.0 GA正式版发布
  7. 一行代码指定python下载源为清华源【只需修改一次】
  8. 进阶之路(基础篇) - 009 通过底层AVR方法实现SPI数据传输
  9. C++17特性一览(转载)
  10. 真羡慕那些能够过目不忘的人
  11. JDK8下载安装教程
  12. WeCode在线少儿编程|为什么我们选择代码编程
  13. 机械专业怎么学matlab,MATLAB在机械类专业课教学中的应用
  14. 联想小新300加固态_Lenovo 联想 小新310 硬盘移位加装SSD
  15. Easy_RL 01:强化学习基础
  16. python的numpy库安装_Python库之numpy库的安装教程
  17. cocos2d_lua 2.5D
  18. 关于Android终端机串口的理解
  19. 手机上好用的apm测试软件,在哪才能找到测apm的软件  及如合使用  – 手机爱问...
  20. Excel中,把数字和汉字分开的方法

热门文章

  1. Python学习记录(小甲鱼C的课程)
  2. stata面板数据gmm回归_gmm的stata操作步骤
  3. 《东周列国志》第二十三回 卫懿公好鹤亡国 齐桓公兴兵伐楚
  4. raid硬盘速度测试软件,RAID 0模式下固态硬盘性能测试
  5. Windows PE(WinPE)
  6. phpnow mysql升级_PHPNOW如何升级PHP
  7. phpnow搭建本地网站服务器,phpnow搭建本地网站服务器
  8. 目标客户画像_分析目标人群画像的5个步骤
  9. php-fpm 端口号,PHP-FPM 配置说明
  10. Building a Hypermedia-Driven RESTful Web Service