`

【java】Java编码字符集与字符集编码入门(六) Java中的增补字符

    博客分类:
  • java
 
阅读更多

    Java号称对Unicode提供天然的支持,这话在很久很久以前就已经是假的了(不过曾经是真的),实际上,到JDK5.0为止,Java才算刚刚跟上Unicode的脚步,开始提供对增补字符的支持。

 

    现在的Unicode码空间为U+0000到U+10FFFF,一共1114112个码位,其中只有1112064个码位是合法的(我来替你做减法,1114112-1112064=2048,也就是说有2048个码位不合法),但并不是说现在的Unicode就有这么多个字符了,实际上其中很多码位还是空闲的,到Unicode 4.0 规范为止,只有96382个码位被分配了字符(但无论如何,仍比很多人认为的65536个字符要多得多了)。其中U+0000 到U+FFFF的部分被称为基本多语言面(Basic Multilingual Plane,BMP)。U+10000及以上的字符称为补充字符。在Java中(Java1.5之后),补充字符使用两个char型变量来表示,这两个char型变量就组成了所谓的surrogate pair(在底层实际上是使用一个int进行表示的)。第一个char型变量的范围称为“高代理部分”(high-surrogates range,从"uD800到"uDBFF,共1024个码位), 第二个char型变量的范围称为low-surrogates range(从"uDC00到"uDFFF,共1024个码位, 高低代理部分合计2048个码位,刚刚好就是那2048个不合法码位),这样使用surrogate pair可以表示的字符数一共是1024*1024,共计1048576个,加上BMP的65536个码位,去掉2048个非法的码位,正好是1112064个码位。

 

    关于Unicode的码空间实际上有一些稍不小心就会让人犯错的地方。比如我们都知道从U+0000到U+FFFF的部分被称为基本多语言面(Basic Multilingual Plane,BMP),这个范围内的字符在使用UTF-16编码时,只需要一个char型变量就可以保存。仔细看看这个范围,应该有65536这么大,因此你会说单字节的UTF-16编码能够表示65536个字符,你也会说Unicode的基本多语言面包含65536个字符,但是再想想刚才说过的surrogate pair,一个UTF-16表示的增补字符(再一次的,需要两个char型变量才能表示的字符)怎样才能被正确的识别为增补字符,而不是两个普通的字符呢?答案你也知道,就是通过看它的第一个char是不是在高代理范围内,第二个char是不是在低代理范围内来决定,这也意味着,高代理和低代理所占的共2048个码位(从0xD800到0xDFFF)是不能分配给其他字符的。

 

    但这是对UTF-16这种编码方法而言,而对Unicode这样的字符集呢?在Unicode的编号中,U+D800到U+DFFF是否有字符分配?答案是也没有!这是典型的字符集为方便编码方法而做的安排(你问他们这么做的目的?当然是希望基本多语言面中的字符和一个char型的UTF-16编码的字符能够一一对应,少些麻烦,从中我们也能看出UTF-16与Unicode间很深的渊源与结合)。也就是说,无论Unicode还是UTF-16编码后的字符,在0x0000至0xFFFF这个范围内,只有63488个字符。这就好比最初的CPU被勉强拿来做多媒体应用,用得多了,CPU就不得不修正自己从硬件上对多媒体应用提供支持了。

 

    尽管不情愿,但说到这里总还得扯扯相关的概念:代码点和代码单元。

 

    代码点(Code Point)就是指Unicode中为字符分配的编号,一个字符只占一个代码点,例如我们说到字符“汉”,它的代码点是U+6C49.代码单元(Code Unit)则是针对编码方法而言,它指的是编码方法中对一个字符编码以后所占的最小存储单元。

    例如UTF-8中,代码单元是一个字节,因为一个字符可以被编码为1个,2个,3个或者4个字节(UTF-8的编码方案允许编码后存储的是1~4个字节);

    在UTF-16中,代码单元变成了两个字节(就是一个char),因为一个字符可以被编码为1个或2个char(即2或4个字节,不存在1或3个字节,你找不到比一个char还小的UTF-16编码的字符,嘿嘿)。说得再罗嗦一点,一个字符,仅仅对应一个代码点,但对于UTF-16的编码方案却可能有两种代码单元(即可能被编码为2个char)。

 

    以上概念绝非学术化的绕口令,这意味着当你想以一种统一的方式指定自己使用什么字符的时候,使用代码点(即你告诉你的程序,你要用Unicode中的第几个字符)总是比使用代码单元更好(因为这样做的话你还得区分情况,有时候提供一个16进制数字,有时候要提供两个)。

 

    例如我们有一个增补字符???(哈哈,你看到了三个问号对吧?因为我的系统显示不出这个字符),它在Unicode中的编号是U+2F81A(范围在U+FFFF之后,属于补增字符),当在程序中需要使用这个字符的时候,就可以这样来写:

   

String s=String.valueOf(Character.toChars(0x2F81A));
char[]chars=s.toCharArray();
for(char c:chars){
    System.out.format("%x",(short)c);
}

 

    后面的for循环把这个字符的UTF-16编码打印了出来,结果是d87edc1a注意到了吗?这个字符变成了两个char型变量,其中0xd87e就是高代理部分的值,0xdc1a就是低代理的值。这两个都处于Unicode的非法值范围中,只要组合起来形成补增字符才能找到对应字符显示,而单个字符在Unicode字符集中没有字符与之对应,所以各自打印出来为问号。

分享到:
评论

相关推荐

    Java中的字符集编码入门(六)Java中的增补字符.doc

    ### Java中的字符集编码入门(六):Java中的增补字符 #### 一、引言 随着全球化进程的加速和技术的发展,字符集编码已经成为软件开发不可或缺的一部分。Java 作为一种广泛使用的编程语言,对于字符集的支持至关...

    香港增补字符集香港增补字符集香港增补字符集香港增补字符集[参照].pdf

    香港增补字符集香港增补字符集香港增补字符集香港增补字符集[参照].pdf

    常用字符集编码详解

    GB18030是中国最新的一套汉字编码标准,兼容GBK和GB2312,并且支持Unicode3.1中所有的中文字符,包括增补汉字,其字符集容量远大于GBK。GB18030的编码范围为0x00至0xFEFE,其中0x00至0x7F与ASCII完全相同,0x81至0...

    香港增補字符集-2001

    香港常用字符集,如有需要可下載!

    常用中文字符

    标签中的“常见中文”和“unicode字符集”强调了这个文件与Unicode编码有关。Unicode是一种广泛采用的字符编码系统,它为每一个字符分配了一个唯一的数字,无论这个字符属于哪种语言。在Unicode中,中文字符通常被...

    编码概述JAVA

    在实际开发中,我们通常会说使用UTF-8编码,实际上是在指使用UTF-8编码方案来处理Unicode字符集。 综上所述,Unicode和UTF-8在JAVA编程中扮演着至关重要的角色,它们不仅解决了多语言环境下的字符编码问题,还提供...

    20081024Unicode字符集扩展及Surrogate[归纳].pdf

    Unicode字符集是编码标准,旨在容纳世界上所有语言的文字,确保数据在不同的计算机系统间能够无缝交换。这个标准是由Unicode联盟制定的,它定义了一个字符到一个数字(代码点)的映射,使得每个字符都有一个唯一的...

    Unicode字符编码范围

    2. **增补拉丁字符集1** (U+0080–U+00FF):增加了重音符号等特殊字符。 3. **拉丁字符扩展集A** (U+0100–U+017F):包含更多用于东欧语言的特殊拉丁字母。 #### 三、非洲文字 1. **N’Ko** (U+07C0–U+07FF):一...

    按GBK编码字库编号整理的7008个国家标准通用字表

    GBK(GB2312扩展版)是中华人民共和国国家标准GB2312-80《信息交换用汉字编码字符集·基本集》的扩展版本,全称《汉字内码扩展规范》,由微软公司与中国国家有关部门共同开发,主要用于解决GB2312字符集所包含的汉字...

    对XML进行parse时的InvalidUnicodecharacter(0x0)分析.pdf

    在Java 5.0及更高版本中,已经包含了对增补字符的支持,使得开发者可以编写处理各种Unicode字符的程序,包括在政府应用、出版软件以及东亚市场中需要的特殊字符。 在处理XML时,为了消除"Invalid Unicode character...

    Java基础教程之字符流文件读写

    char类型被定义为两个字节大小,可以存储一个字符,但对于一些增补字符集来说,往往会使用两个char来表示一个字符。 在学习字符流之前,需要了解Java中的文件字节流框架。字节流处理文件的时候是基于字节的,而字符...

    什么是C语言中的宽字符与多字节字符

    C语言原本是在英文环境中设计的,主要的字符集是7位的ASCII码,8位的byte(字节)是常见的字符编码单位。但是国际化软件必须能够表示不同的字符,而这些字符数量庞大,无法使用一个字节编码。  C95标准化了两种...

    Java Platform Migration Guide.pdf

    Java 5.0提供了对增补Unicode字符集的全面支持,这对于处理多种语言的应用程序非常重要。 ##### 网络(Networking) **1.4.1 URLConnection Processing** 在处理URL连接方面,Java 5.0增加了新的功能并修复了一些...

    EDA/PLD中的什么是C语言中的宽字符与多字节字符

    C语言原本是在英文环境中设计的,主要的字符集是7位的ASCII码,8位的byte(字节)是最常见的字符编码单位。但是国际化软件必须能够表示不同的字符,而这些字符数量庞大,无法使用一个字节编码。  C95标准化了两种...

    VB簡繁轉化(简繁转换)

    这是因为简繁转换并不像单纯的编码转换那么简单,涉及到的是字符集的对应关系和转换规则,多次转换可能导致字符对应关系混乱。因此,为了防止数据丢失,强烈建议在转换前对原始代码进行备份。 在进行简繁转换时,...

    UniCode编码、简繁体互转在Delphi中的应用

    另一方面,`OpenCC4Delphi`是基于OpenCC开源项目的Delphi封装,OpenCC是一个强大的简繁体转换工具,提供了多种转换规则,如“常用简体字->繁体字”、“香港增补字符集”等。在Delphi中使用`OpenCC4Delphi`,你需要先...

    Scala语言规范.docx

    - **字符集**:Scala程序使用的字符集是Unicode的基本多文种平面字符集,目前不支持Unicode中增补的字符。 - **模式**:Scala定义了两种模式——Scala模式和XML模式。如果没有特别说明,对Scala符号的描述通常是指...

    MISRA C 2004.doc

    3.2 应记录字符集和相应的编码,以便团队成员和其他开发者了解代码使用的字符集。 3.3 应确定、记录并考虑所选编译器中整数除法的实现,因为不同的编译器可能有不同的处理方式。 3.4 使用#pragma指令的所有地方都应...

    条形码生成FreeBarcode

    \STARTBabcdef\CODEC123456,意思是:以以字符集B(\STARTB)开始,编码abcdef,转入字符集C(\CODEC) 编码123456。 所以,128条码是比较复杂的,而现在大多数条码软件只支持128A\B\C,且不支持带控制符号的 128A\B\...

Global site tag (gtag.js) - Google Analytics