欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

浅谈Java中Unicode的编码和实现

程序员文章站 2024-04-02 09:21:28
unicode的编码和实现 大概来说,unicode编码系统可分为编码方式和实现方式两个层次。 编码方式 字符是抽象的最小文本单位。它没有固定的形状(可能是一...

unicode的编码和实现

大概来说,unicode编码系统可分为编码方式和实现方式两个层次。

编码方式

字符是抽象的最小文本单位。它没有固定的形状(可能是一个字形),而且没有值。“a”是一个字符,“€”也是一个字符。字符集是字符的集合。编码字符集是一个字符集,它为每一个字符分配一个唯一数字。

unicode 最初设计是作为一种固定宽度的 16 位字符编码。也就是每个字符占用2个字节。这样理论上一共最多可以表示216(即65536)个字符。上述16位统一码字符构成基本多文种平面。基本多文种平面的字符的编码为u+hhhh,其中每个h代表一个十六进制数字。

很明显,16 位编码的所有 65,536 个字符并不能完全表示全世界所有正在使用或曾经使用的字符。于是,unicode 标准已扩展到包含多达 1,112,064 个字符。那些超出原来的 16 位限制的字符被称作增补字符。unicode 标准 2.0 版是第一个包含

启用增补字符设计的版本,但是,直到 3.1 版才收入第一批增补字符集。

unicode字符平面映射

目前的unicode字元分为17组编排,每组称为平面(plane),而每平面拥有65536(即216)个代码点。然而目前只用了少数平面。

平面 始末字元值 中文名称 英文名称
0号平面 u+0000 - u+ffff 基本多文种平面 basic multilingual plane,简称bmp
1号平面 u+10000 - u+1ffff 多文种补充平面 supplementary multilingual plane,简称smp
2号平面 u+20000 - u+2ffff 表意文字补充平面 supplementary ideographic plane,简称sip
3号平面 u+30000 - u+3ffff 表意文字第三平面(未正式使用) tertiary ideographic plane,简称tip
4号平面

13号平面
u+40000 - u+dffff (尚未使用)  
14号平面 u+e0000 - u+effff 特别用途补充平面 supplementary special-purpose plane,简称ssp
15号平面 u+f0000 - u+fffff 保留作为私人使用区(a区)
private use area-a,简称pua-a
16号平面 u+100000 - u+10ffff 保留作为私人使用区(b区)
private use area-b,简称pua-b

增补字符是代码点在 u+10000 至 u+10ffff 范围之间的字符(上述表格中1号平面~16号平面之间的),也就是那些使用原始的 unicode 的 16 位设计无法表示的字符。从 u+0000 至 u+ffff 之间的字符集有时候被称为基本多语言面 (bmp)。因此,每一个 unicode 字符要么属于 bmp,要么属于增补字符。

实现方式

utf-32、utf-16 和 utf-8 是具体的实现方案。unicode的实现方式不同于编码方式。一个字符的unicode编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对unicode编码的实现方式有所不同。unicode的实现方式称为unicode转换格式(unicode transformation format,简称为utf)。

例如,如果一个仅包含基本7位ascii字符的unicode文件,如果每个字符都使用2字节的原unicode编码传输,其第一字节的8位始终为0。这就造成了比较大的浪费。对于这种情况,可以使用utf-8编码,这是一种变长编码,它将基本7位ascii字符仍用7位编码表示,占用一个字节(首位补0)。而遇到与其他unicode字符混合的情况,将按一定算法转换,每个字符使用1-3个字节编码,并利用首位为0或1进行识别。这样对以7位ascii字符为主的西文文档就大幅节省了编码长度(具体方案参见utf-8)。类似的,对未来会出现的需要4个字节的辅助平面字符和其他ucs-4扩充字符,2字节编码的utf-16也需要通过一定的算法进行转换。

再如,如果直接使用与unicode编码一致(仅限于bmp字符)的utf-16编码,由于每个字符占用了两个字节,在麦金塔电脑(mac)机和个人电脑上,对字节顺序的理解是不一致的。这时同一字节流可能会被解释为不同内容,如某字符为十六进制编码4e59,按两个字节拆分为4e和59,在mac上读取时是从低字节开始,那么在mac os会认为此4e59编码为594e,找到的字符为“奎”,而在windows上从高字节开始读取,则编码为u+4e59的字符为“乙”。就是说在windows下以utf-16编码保存一个字符“乙”,在mac os环境下打开会显示成“奎”。此类情况说明utf-16的编码顺序若不加以人为定义就可能发生混淆,于是在utf-16编码实现方式中使用了大端序(big-endian,简写为utf-16 be)、小端序(little-endian,简写为utf-16 le)的概念,以及可附加的字节顺序记号解决方案,目前在pc机上的windows系统和linux系统对于utf-16编码默认使用utf-16 le。(具体方案参见utf-16)

此外unicode的实现方式还包括utf-7、punycode、cesu-8、scsu、utf-32、gb18030等,这些实现方式有些仅在一定的国家和地区使用,有些则属于未来的规划方式。目前通用的实现方式是utf-16小端序(le)、utf-16大端序(be)和utf-8。在微软公司windows xp附带的记事本(notepad)中,“另存为”对话框可以选择的四种编码方式除去非unicode编码的ansi(对于英文系统即ascii编码,中文系统则为gb2312或big5编码)外,其余三种为“unicode”(对应utf-16 le)、“unicode big endian”(对应utf-16 be)和“utf-8”。

代码点、码位

在字符编码术语中,码位或称编码位置,即英文的code point或code position,是组成码空间(或代码页)的数值。 例如,ascii码包含128个码位,范围是016进制到7f16进制,扩展ascii码包含256个码位,范围是016进制到ff16进制,而unicode包含1,114,112个码位,范围是016进制到10ffff16进制。unicode码空间划分为17个unicode字符平面(基本多文种平面,16个辅助平面),每个平面有65,536(= 216)个码位。因此unicode码空间总计是17 × 65,536 = 1,114,112.

代码单元、码元

码元(code unit,也称“代码单元”)是指一个已编码的文本中具有最短的比特组合的单元。对于utf-8来说,码元是8比特长;对于utf-16来说,码元是16比特长;对于utf-32来说,码元是32比特长。码值(code value)是过时的用法。
明白了上述两个概念,我们就可以认为utf-n(n为8,16,32)干的事就是把unicode字符集的抽象码位映射为n位长的整数(即码元)的序列,用于数据存储或传递。

utf-32 即将每一个 unicode 代码点表示为相同值的 32 位整数。很明显,它是内部处理最方便的表达方式,但是,如果作为一般字符串表达方式,则要消耗更多的内存。

utf-16 使用一个或两个未分配的 16 位代码单元的序列对 unicode 代码点进行编码。值 u+0000 至 u+ffff 编码为一个相同值的 16 位单元。增补字符编码为两个代码单元,第一个单元来自于高代理范围(u+d800 至 u+dbff),第二个单元来自于低代理范围(u+dc00 至 u+dfff)。这在概念上可能看起来类似于多字节编码,但是其中有一个重要区别:值 u+d800 至 u+dfff 保留用于 utf-16;没有这些值分配字符作为代码点。这意味着,对于一个字符串中的每个单独的代码单元,软件可以识别是否该代码单元表示某个单单元字符,或者是否该代码单元是某个双单元字符的第一个或第二单元。这相当于某些传统的多字节字符编码来说是一个显著的改进,在传统的多字节字符编码中,字节值 0x41 既可能表示字母“a”,也可能是一个双字节字符的第二个字节。

utf-8 使用一至四个字节的序列对编码 unicode 代码点进行编码。u+0000 至 u+007f 使用一个字节编码,u+0080 至 u+07ff 使用两个字节,u+0800 至 u+ffff 使用三个字节,而 u+10000 至 u+10ffff 使用四个字节。utf-8 设计原理为:字节值 0x00 至 0x7f 始终表示代码点 u+0000 至 u+007f(basic latin 字符子集,它对应 ascii 字符集)。这些字节值永远不会表示其他代码点,这一特性使 utf-8 可以很方便地在软件中将特殊的含义赋予某些 ascii 字符。

下表所示为几个字符不同表达方式的比较:

unicode 代码点 u+0041 u+00df u+6771 u+10400
表示字形
utf-32 代码单元
00000041
000000df
00006771
00010400
utf-16 代码单元
0041
00df
6771
d801 dc00
utf-8 代码单元
41
c3 9f
e6 9d b1
f0 90 90 80

注:上述编码中的数字均是十六进制表示的。

总结

以上就是本文关于浅谈java中unicode的编码和实现的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:java编程将汉字转unicode码代码示例java源码解析之object类等,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!