Unicode编码及其实现:UTF-16、UTF-8,and more

本文主要讨论Unicode的编码与各种实现,着重讨论UTF-16,UTF-8的实现规则,以及Big-endian和Little-Endian的存储规则。


一、Unicode编码

    Unicode出现之前已经有各种编码标准:ANSI、ISO8859-1、GB2312、GBK以及BIG-5等。Unicode试图统一各种编码,在Unicode演进过程中,也有自身不断修复的过程:刚开始的时候认为16位可以表达65535个字符,已经足够收集所有的字符;后来随着大量中文、韩文和日文等表意文字的加入,已经超出了65535个字符,16位已经不能描述所有的字符集了。

    在Unicode字符集中的某个字符对应的代码值,称作代码点(Code Point),用16进制书写,并加上U+前缀。比如,‘田’的代码点是U+7530;‘A’的代码点是U+0041。

    前面说过,Unicode的字符已经超过16位所能表达的范围,把所有这些CodePoint分成17个代码平面(Code Plane)

  • U+0000 ~ U+FFFF划入基本多语言平面(Basic MultilingualPlane,简记为BMP);
  • 其余划入16个辅助平面(Supplementary Plane),代码点范围U+10000 ~ U+10FFFF

    虽然这样划分,但并不是每个Plane中的Codepoint都对应有字符,这里面有保留的,还有特殊用途的。


二、Unicode编码的实现


    Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的,但是在实际存储和传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式(UnicodeTransformation Format,简称为UTF)。

    对Unicode编码的实现方式有UTF-16BE、UTF-16LE、UTF-8、UTF-7以及UTF-32等实现方式,目前通用的实现方式是UTF-16LE、UTF-16BE和UTF-8。


2.1 UTF-16

    UTF-16是用16bit编码来表达Unicode,这样表达范围是216(即65536)。如果表达BMP内的字符,用一个UTF-16就可表达,对于辅助平面内的字符,UTF-16有巧妙的设计。

    BMP内,从U+D800U+DFFF之间的码位区段是永久保留不映射到字符, UTF-16利用保留下来的0xD800-0xDFFF区段的码位来对辅助平面的字符的码位进行编码。


对U+0000 ~ U+D7FF以及U+E000 ~ U+FFFF的编码

    UTF-16与UCS-2编码这个范围内的码位为单个16比特长的码元,数值等价于对应的码位。BMP中的这些码位是仅有的码位可以在UCS-2被表示。

对U+10000 ~ U+10FFFF的编码

    辅助平面(Supplementary Planes)中的码位,在UTF-16中被编码为一对16比特长的码元(即32bit,4Bytes),称作代理对(surrogatepair)。


 具体方法是:

UTF-16解码

hi \ lo

DC00

DC01

   …   

DFFF

D800

10000

10001

103FF

D801

10400

10401

107FF

  

DBFF

10FC00

10FC01

10FFFF

  1. 码位减去0x10000, 得到的值是长度为20bit(0..0xFFFFF);
  2. 步骤1得到数值的高位的10比特的值(值范围为0..0x3FF)被加上0xD800得到第一个码元或称作高位代理(high surrogate)或前导代理(lead surrogate)。值的范围是0xD800..0xDBFF
  3. 步骤1得到数值的低位的10比特的值(值范围为0..0x3FF)被加上0xDC00得到第二个码元或称作低位代理(low surrogate)或后尾代理(trail surrogate)。值的范围是0xDC00..0xDFFF

    这样,这个范围内的字符就被编码成了一个代理对[lead surrogate,trail surrogate]:两个16bits码元,取值范围分别是0xD800..0xDBFF,0xDC00..0xDFF。而BMP中得到的码元范围0x0000..0xFFFF中,0xD800..0xDFFF又是保留的,所以这三个区段是相互不重叠的,在解码时很容易实现。UTF-16解码高位代理+低位代理得到的码元与码位的对应关系如上表所示:

    下面以对U+64321的UTF-16编码为例,看一下对于辅助平面内的字符的编码实现:

V  = 0x64321

Vx = V - 0x10000

   = 0x54321

   = 01010100 0011 0010 0001

 

Vh = 01 0101 0000 // Vx 的高位部份的 10 bits

Vl = 11 0010 0001 // Vx 的低位部份的 10 bits

w1 = 0xD800 //结果的前16位元初始值

w2 = 0xDC00 //结果的后16位元初始值

 

w1 = w1 | Vh

   = 1101 1000 0000 0000

   |       01 0101 0000

   = 1101 1001 0101 0000

   = 0xD950

 

w2 = w2 | Vl

   = 1101 1100 0000 0000

   |       11 0010 0001

   = 1101 1111 0010 0001

   = 0xDF21

    所以这个字 U+64321 最后的 UTF-16 编码是:

0xD950 0xDF21


对于生成的编码,因为对于16Bits的两字节,还有存取先后的问题,还有Endian的问题,这在后续讲述。


2.2 UTF-8

    UTF-8(8-bitUnicode Transformation Format)是一种针对Unicode的可变长度字符编码,使用一至四个字节为每个字符编码:

  •  Unicode范围为U+0000..U+007F 的128个ASCII字符只需一个字节编码;
  •  Unicode范围为U+0080..U+07FF的字符需要二个字节编码;
  •  Unicode范围为U+0800..U+FFFF的其他BMP中的字符(这包含了大部分常用字)使用三个字节编码;
  •  Unicode 辅助平面的字符(其他极少使用的字符)使用四字节编码。

    对上述提及的第四种字符而言,UTF-8使用四个字节来编码似乎太耗费资源了。但UTF-8对所有常用的字符都只用三个字节表达,而且UTF-16编码对前述的第四种字符同样需要四个字节来编码,而如果是ASCII居多的字符,UTF-8能极大的节约存储空间。UTF-8逐渐成为电子邮件、网页及其他储存或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。互联网邮件联盟(IMC)建议所有电子邮件软件都支持UTF-8编码。


    对CodePoint各个范围内的字符进行UTF-8编码的规则如下:

Code point

UTF-8字节流

U+00000000 – U+0000007F

0xxxxxxx

U+00000080 – U+000007FF

110xxxxx 10xxxxxx

U+00000800 – U+0000FFFF

1110xxxx 10xxxxxx 10xxxxxx

U+00010000 – U+001FFFFF

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

其中,U+D800到U+DFFF之间的区段在Unicode的定义中没有具体字符使用的,被用来在UTF-16编码中对辅助平面的字符进行编码。


    下面以“田”(CodePoint为U+7530)为例,看如何对其进行UTF-8编码:

  •  U+7530落在U+0800..U+FFFF区间,采用三字节编码;
  •  0x7530转换为二进制为111 010100 110000;
  •  代入表中,得到111001111001010010110000

    这样,得到“田”(U+7530)的UTF-8编码:0xE7 94 B0。


    知道UTF-8的编码规则,我们可以对于UTF-8编码中的任意字节B,进行下面解码:

  •  如果B的第一位为0,则B为ASCII码,并且B独立的表示一个字符;如果B的第一位为1,第二位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的一个字节,并且不为字符的第一个字节编码(字符的第一个字节之外的后编码);
  •  如果B的前两位为1,第三位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的第一个字节,并且该字符由两个字节表示;
  •  如果B的前三位为1,第四位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的第一个字节,并且该字符由三个字节表示;
  •  如果B的前四位为1,第五位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的第一个字节,并且该字符由四个字节表示。

 

2.3 UCS-2 vs UTF-16,UCS-4 vs UTF-32

    UCS-2每个字符占用2个字节。UCS-2是UTF-16的子集。在没有辅助平面前,UTF-16与UCS-2所指的是同一的意思。但当引入辅助平面字符后,UTF-16加入了对辅助平面内的字符的支持。现在若有软件声称自己支持UCS-2编码,那其实是暗指它不支持UTF-16中超过2bytes的字集。亦即,对于小于0x10000的UCS码,UTF-16编码就等于UCS码。Java早期版本对Unicode的支持,就只是UCS-2的支持,现在加入了对UTF-16的完整支持。

 

    UCS-4UTF-32的意义一致,对每个字符都使用4字节(31位字符集,加上恒为0的首位,共需占据32位)。理论上最多能表示231个字符,完全可以涵盖一切语言所用的符号。虽然每一个码位使用固定长定的字节看似方便,对于普通只需要2个字节存储的常用字占绝大对数的字符集来说,却极大的浪费了空间,并没怎么得到应用。


三、Big-Endian/Little-Endian与BOM

    在讲UTF-16编码方式时说到,最终生成的编码可能是2个字节(BMP内的字符),这两个字节在传输和存储过程中,高/低位位置不同,是不同的字符。比如,“田”的UTF-16编码是0x7530,但是如果存成0x3075,就变成了“ふ”,另外的字符。

    所以,为了识别一个编码过的字符的存储顺序,必须用特殊字符来指示。Unicode字符中U+FEFF被用来指示这种存储顺序,被称作Byte Order Mark(BOM)。

  •  Big-Endian:最低位地址存放高位字节,可称高位优先,内存从最低地址开始按顺序存放(高数位数字先写)。最高位字节放最前面。
  •  Little Endian:最低位地址存放低位字节,可称低位优先,内存从最低地址开始按顺序存放(低数位数字先写)。最低位字节放最前面。

    所以,BOM在Big-Endian系统上存储为FE FF;而在Big-Endian系统上存储则为FF FE。在以Big-Endian存储的UTF-16(UTF-16BE)的文件的开头,用FEFF指示;以Little-Endian存储的UTF-16(UTF-16LE)的文件的开头,用FEFF指示。

    在Windows的记事本上,另存为的时候,你可以选择不同的Endian存储,然后再用纯文本编辑工具(Ultra-edit)来检验一下,UTF-16的存储顺序。

    BOM的UTF-8编码为11101111 1011101110111111 (EF BB BF),所以一般EF BB BF被放在文本的开头,用来指示其编码为UTF-8。


【附】基本概念对照

Code Point码位

Code Unit码元是指一个已编码的文本中具有最短的比特组合的单元。对于UTF-8来说,码元是8比特长;对于UTF-16来说,码元是16比特长;对于UTF-32来说,码元是32比特长。

BMP - Basic Multilingual Plane

UTF - Unicode Transformation Format

BOM – Byte Order Mark

UCS - Universal Character Set

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/452059.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apache Tiles的使用 前配置

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 使用方法见&#xff1a; http://blog.csdn.net/jiangyu1013/article/details/53161580 1.加maven 依赖&#xff1a; <!-- 页面布局…

day212223:线程、进程、协程

1、程序工作原理 进程的限制&#xff1a;每一个时刻只能有一个线程来工作。多进程的优点&#xff1a;同时利用多个cpu&#xff0c;能够同时进行多个操作。缺点&#xff1a;对内存消耗比较高当进程数多于cpu数量的时候会导致不能被调用&#xff0c;进程不是越多越好&#xff0c;…

php课程 8-28 php如何绘制生成显示图片

php课程 8-28 php如何绘制生成显示图片 一、总结 一句话总结&#xff1a;gd库轻松解决 1、php图片操作生成的图的两种去向是什么&#xff1f; 一种在页面直接输出&#xff0c;一种存进本地磁盘 2、php操作图片的库有哪些&#xff1f; PHP: Image Processing and Generation - M…

代码行技术

用代码行技术估算软件规模时&#xff0c;当程序较小时常用的单位是代码行数&#xff08;LOC&#xff09;&#xff0c;当程序较大时常用的单位是千行代码数&#xff08;KLOC&#xff09;。 代码行技术的主要优点是&#xff0c;代码是所有软件开发项目都有的“产品”&#xff0c;…

网络爬虫--8.编码趣闻

很久很久以前&#xff0c;有一群人&#xff0c;他们决定用8个可以开合的晶体管来组合成不同的状态&#xff0c;以表示世界上的万物。他们看到8个开关状态是好的&#xff0c;于是他们把这称为"字节"。 再后来&#xff0c;他们又做了一些可以处理这些字节的机器&#…

科技领域的一分钟

各位果迷是否能想象在一分钟之内&#xff0c;科技领域都会发生什么事情&#xff1f;——苹果平均每分钟卖出81部 iPad&#xff1b;在 iPhone 4S 发布后的第一个周末&#xff0c;每分钟卖出925部 iPhone 4S&#xff1b;RIM每分钟卖出103台黑莓手机&#xff1b;Amazon每分钟卖出1…

flavr—超级漂亮的jQuery扁平弹出对话框

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 插件描述&#xff1a;flavr是一个时尚的扁平弹出对话框为您的下一个网站。 flavr是响应设计布局&#xff0c;能够适应任何屏幕大小。 得…

经纬度之间的距离计算

来自谷歌地图的计算公式&#xff1a; 通过JAVA的Math类各种方法调用。实现上述公式 private static double EARTH_RADIUS 6378.137;// 单位千米/*** 角度弧度计算公式 rad:(). <br/>* * 360度2π πMath.PI* * x度 x*π/360 弧度* * author chiwei* param d* return* s…

在CentOS7阿里云服务器部署ThinkPHP5,并配置phpstrom实现同步开发(微信小程序及管理员后端)...

小程序和后端同步开发 1.服务器安装tp5框架&#xff1a; 方法很多比如&#xff1a;github、linux命令直接手动下、composer 都可以&#xff0c;方法很多&#xff0c;百度一下&#xff0c;不再累述 2.这时你会发现怎么都访问出现不了这个令人舒心的界面&#xff08;ok第一个坑到…

ER图( 实体联系图)

E-R图也称实体-联系图(Entity Relationship Diagram)&#xff0c;提供了表示实体类型、属性和联系的方法&#xff0c;用来描述现实世界的概念模型。 它是描述现实世界概念结构模型的有效方法。是表示概念模型的一种方式&#xff0c;用矩形表示实体型&#xff0c;矩形框内写明…

网络爬虫--9.正则表达式

文章目录一. 正则表达式1.为什么要学正则表达式2.什么是正则表达式3.正则表达式匹配规则二. Python 的 re 模块1.re 模块的一般使用步骤2.compile 函数3.match 方法4.search 方法5.findall 方法6.finditer 方法7.split 方法8.sub 方法9.匹配中文10.贪婪模式与非贪婪模式1&#…

概念模型

将需求分析得到的用户需求抽象为信息结构&#xff08;即概念模型&#xff09;的过程就是概念结构设计 概念模型的特点 &#xff08;1&#xff09;能真实、充分地反映现实世界&#xff0c;是现实世界的一个真 实模型。 &#xff08;2&#xff09;易于理解&#xff0c;从…

笔记本电池的正确使用方法

一、新买笔记本不需要激活&#xff0c;也不需要前三次的充电12小时深充深放&#xff0c;这主要是锂电池的原理和特性决定的。电池设计有电量保护&#xff0c;不可能将电量完全用完&#xff0c;当然也不可能过度充电。 二、笔记本电池的寿命受周围环境的影响很大&#xff0c;最好…

关于XShell 启动虚拟机的weblogic并在本地打开oracle-weblogic 有关部署

对于没有用过这款软件的童鞋&#xff0c;我想必定会有几步弯路&#xff1a; 1.新建好的虚拟机记得换成root用户【su root】~ifconfig【eth0 inet addr】如果没有这项请点击右上角的电脑标识&#xff0c;鼠标左击一下连接&#xff0c;没有了x号就重新输入ifconfig就有了 2.xshe…

JQuery Datatables Dom 和 Language 参数详细说明

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Dom说明 定义表格控件在页面的显示顺序。 每个控件元素在数据表都有一个关联的单个字母。 l - 每页显示行数的控件f - 检索条件的控件…

程序员的思维修炼》读书笔记

PB15061359 王亚正 这本书主要是从思维角度上来写的&#xff0c;不具体针对到程序员如何写代码。我觉得这本书不仅仅适合程序员&#xff0c;其他对各行各业的人都同样适用。 书中首先讲了新手和专家的区别&#xff0c;一个需要靠规则&#xff0c;另一个则是靠感觉。 之后介绍了…

网络爬虫--10.使用正则表达式的爬虫

文章目录一. 前言二. 第一步&#xff1a;获取数据三. 第二步&#xff1a;筛选数据四. 第三步&#xff1a;保存数据五. 第四步&#xff1a;实现循环抓取一. 前言 现在拥有了正则表达式这把神兵利器&#xff0c;我们就可以进行对爬取到的全部网页源代码进行筛选了。 下面我们一…

一对一 一对多 多对多

一对一 例如&#xff0c;学校里一个班级只有一个正班长&#xff0c;而一个班长只在一个班中任职&#xff0c;则班级与班长之间具有一对一联系。 一对多 例如&#xff0c;一个班级中有若干名学生&#xff0c;而每个学生只在一个班级中学习&#xff0c;则班级与学生之间具有一…

Mac下的Jenkins安装

安装方式 1&#xff09;通过命令行安装 brew install jenkins&#xff0c;可能会遇到先更新 brew 的情况 https://brew.sh/index_zh-cn&#xff1b; 2&#xff09;通过 pkg 安装&#xff0c;官方网址&#xff1a;https://jenkins.io/ 安装完成后&#xff0c;会自动打开浏览器…

Order By 排序条件中带参数的写法(Oracle数据库、MyBatis)

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 sortWay 是参数。 当sortWay 为 llpx 就 ORDER BY FORMAT ASC&#xff0c;为 btypx 就ORDER BY BID DESC &#xff0c;为 zhpx 就 ORDE…