1
       ---对unicode编码和java代码单元问题研究总结

前言:最近在《java编程思想》一书中看到了代码点与代码单元的概念,当中介绍了java采用UTF-16编码。一个代码单元(code unit)大小为两字节16bit,但是部分字符需要用两个代码单元表示,所以对java中可表示字符集统称为代码点(code point)。当时的认识是中文字符要用两个代码单元表示,其它字符用一个代码单元表示。直到在segmentFault上看到一个问答,才发现自己的理解是错的,因此抽出对unicode做了一个全面的了解。

本文主要想解释一下几个问题:

1、什么是unicode,它和通常所说的UTF是什么关系
2、字符平面(plan)是什么
3、如何用两个代码单元表示一个非基本字符

unicode

unicode是一种编码标准,它是为解决早起ISO编码不兼容问题而提出的。它不仅包括了如何表示一个字符,还有对字符属性特征的定义。【图】在还没有unicode编码的时候,每个国家都有自己的一套编码标准,这样就会发现在两个用不同编码标准实现的计算机之间传输数据几乎是不可能的事情,当时也没有兼容多种语言的计算机。为了大家交流方便,于是各种标准委员会就成立了,制定出了能够兼容所有字符的编码标准--unicode。起初这个委员没有认识到我国博大精深的语言文化,认为用16bit(2^16=65536)已经足以表示世界上的任何一个字符。但当他们看到中国汉语字典的时候为时已晚。于是不得不拓展编码位数,来兼容这些语言。当然现在流通的主流字符还是用一个代码单元16bit来编码的。

    所以unicode是一种编码标准,目标将世界上的每一个字符用统一二进制数字来表示。

UTF(Unicode Transformation Format)

那么utf又是什么?Unicode编码体系分为两部分:编码方式实现方式。编码方式描述了字符和数字的对应关系,对应的是一个通用的编码集合(UCS)。例如它用16bit编码构成了基本字符平面,即我们常用的一些字符集合。然后用21bit编码构成了16个辅助字符平面。这种对字符的定义就是编码方式。
UTF是编码的实现方式,统一字符集(UCS)就是一张编好的大表,至于如何去实现它,就是UTF统一转换格式的责任。统一字符集就像一个一个的字母,字母要转换成可以交流的语言。于是有了各种各样的语言,UTF-8,UTF-16,等等,有的转换格式省空间,有的转换格式容易实现等等。具体用哪一种实现方式完全取决于个人的爱好,但只有两台计算机和软件采用同一种编码方式,所得到的结果才会是相同的。就像有些日本字看起来像汉字却有着不同的意义。

       所以UTF是对统一字符集的编码实现方式。

字符平面

字符平面不用过多详细的解释,委员会对不同的编码范围进行了划分,例如0号平面对应的编码范围是:U+0000~U+FFFF,这又称为基本字符平面简称(BMP)是用一个代码单元编码的,也是我们平时最常见的字符集。另外对于超过16bit编码的字符,委员会定义了16个辅助字符平面。每一个平面都有字符范围的定义。具体可以参考:https://weiji.ga/zh-hans/Unic...

最后详细讲将一下UTF-16实现

首先看一个比较奇怪的汉子:“?” 它的unicode编码为 U+23515 它的UTF-16表示为:\ud84d\udd15。这是如何转换的呢?
再考虑一个问题:“\u642d\u5676\u662f\u6253\u53d1\u65af\u8482\u82ac”这是网络上的一串经过utf-16编码的字符串。其中有用一个代码单元编码的,有用两个代码单元编码的。浏览器或者我们的文本编辑器如何区分呢?

首先,先说明第二个问题。unicode编码期间有一段区间码是保留的,保留的范围是0xD800~0xDc00 ,这段字符码不表示任何字符。浏览器或编辑器从左向右解析字符串,如果编码在这个范围之外,则证明属于基本字符平面的字符,之用一个代码单元表示,在这个范围之内的,则是需要用两个代码单元表示的字符。
转化算法: 一起来做个计算题

我们要转换汉字“?”格式的编码为U+23515,最后结果应该为\ud84d\udd15

v=0x23515
v'=0x23515-0x10000 = 0x13515 = 0001 0011 0101 0001 0101

vh = 0001001101 // 高十位
vl = 0100010101 // 低十位

w1=0xD800 = 1101 1000 0000 0000
w2=0xDc00 = 1101 1100 0000 0000//保留数字范围

w1'= w1|vh = 1101 1000 0100 1101 = 0xd84d
w2'= w2|vl = 1101 1101 0001 0101 = 0xdd15

至此我的疑惑解决了,当然还有很多问题,希望能和大家一起讨论~

参考链接:
维基百科 https://zh.wikipedia.org/wiki...
wiki字符平面:https://weiji.ga/zh-hans/Unic...
计算方法 http://tieba.baidu.com/p/3677...
segment提问帖: https://segmentfault.com/q/10...
《java核心技术》char字符类型一节


xiaotian
12 声望1 粉丝