新网创想网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这些应该是从Unicode标准而来的术语,Unicode标准的核心是一个编码字符集,它为每一个字符分配一个唯一数字。Unicode标准始终使用16进制数字,并且在书写时在前面加上U+,如字符“A”的编码为“U+0041”。
让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:主机域名、网页空间、营销软件、网站建设、掇刀网站维护、网站推广。
代码点是指可用于编码字符集的数字。编码字符集定义一个有效的代码点范围,但是并不一定将字符分配给所有这些代码点。有效的Unicode代码点范围是U+0000至U+10FFFF。Unicode4.0将字符分配给一百多万个代码点中的96382个代码点。
代码单元可以理解为字符编码的一个基本单元,最常用的代码单元是字节(即8位),但是16位和32位整数也可以用于内部处理。
就Unicode标准来说,它的编码字符集有三种编码方案:UTF-32、UTF-16、UTF-8。UTF-32使用32位的代码单元表示一个Unicode代码点,UTF-16使用一个或两个16位的代码单元的序列对Unicode代码点进行编码,UTF-8 使用1至4个字节的序列对Unicode代码点进行编码。
java的char是2字节,16bit,包含所有ascii字符,而且更多,api文档里有描述
char的数据是通过 UnicodeData 文件中的信息定义的,该文件是 Unicode Consortium 维护的 Unicode Character Database 的一部分。此文件指定了各种属性,其中包括每个已定义 Unicode 代码点或字符范围的名称和常规类别。
此文件及其描述可从 Unicode Consortium 获得,网址如下:
Unicode 字符表示形式
char 数据类型(和 Character 对象封装的值)基于原始的 Unicode 规范,将字符定义为固定宽度的 16 位实体。Unicode 标准曾做过修改,以允许那些其表示形式需要超过 16 位的字符。合法代码点 的范围现在是从 U+0000 到 U+10FFFF,即通常所说的 Unicode 标量值。(请参阅 Unicode 标准中 U+n 表示法的定义。)
从 U+0000 到 U+FFFF 的字符集有时也称为 Basic Multilingual Plane (BMP)。代码点大于 U+FFFF 的字符称为增补字符。Java 2 平台在 char 数组以及 String 和 StringBuffer 类中使用 UTF-16 表示形式。在这种表现形式中,增补字符表示为一对 char 值,第一个值取自高代理项 范围,即 (\uD800-\uDBFF),第二个值取自低代理项 范围,即 (\uDC00-\uDFFF)。
所以,char 值表示 Basic Multilingual Plane (BMP) 代码点,其中包括代理项代码点,或 UTF-16 编码的代码单元。int 值表示所有 Unicode 代码点,包括增补代码点。int 的 21 个低位(最低有效位)用于表示 Unicode 代码点,并且 11 个高位(最高有效位)必须为零。除非另有指定,否则与增补字符和代理项 char 值有关的行为如下:
只接受一个 char 值的方法无法支持增补字符。它们将代理项字符范围内的 char 值视为未定义字符。例如,Character.isLetter('\uD840') 返回 false,即使是特定值,如果在字符串的后面跟着任何低代理项值,那么它将表示一个字母。
接受一个 int 值的方法支持所有 Unicode 字符,其中包括增补字符。例如,Character.isLetter(0x2F81A) 返回 true,因为代码点值表示一个字母(一个 CJK 象形文字)。
在 Java SE API 文档中,Unicode 代码点 用于范围在 U+0000 与 U+10FFFF 之间的字符值,而 Unicode 代码点 用于作为 UTF-16 编码的代码单元的 16 位 char 值。有关 Unicode 技术的详细信息,请参阅 Unicode Glossary。
String的offsetByCodePoints(int index, int codePointOffset)方法返回此 String 中从给定的 index 处偏移 codePointOffset 个代码点的索引。
所以4就是从0开始往后偏移4后的索引。
codePointAt(int index)方法是返回指定索引处的字符。
在索引为4处的字符为‘o’,它对应的ASCII码为111
代码点就是指javascript型的信息点而代码单元指普遍的广泛的jinmk 和gdp信息技术网
一、char 码点和代码单元
在Java Core 卷1中 对Char的描述如下
在设计Java时决定采用16位的Unicode字符集....(中间省略)... 现在16位的Char类型已经不能满足描述所有Unicode字符的需要了。
Java为了解决这个问题的方法是使用码点和代码单元
代码点(Code Point):在 Unicode 代码空间中的一个值,取值 0x0 至 0x10FFFF,代表一个字符。
代码单元(Code Unit):在具体编码形式中的最小单位。比如 UTF-16 中一个 code unit 为 16 bits,UTF-8 中一个 code unit 为 8 bits。一个 code point 可能由一个或多个 code unit(s) 表示。在 U+10000 之前的 code point 可以由一个 UTF-16 code unit 表示,U+10000 及之后的 code point 要由两个 UTF-16 code units 表示
在Java中,char类型描述了UTF-16编码中的一个代码单元
码点:就是某个任意字符在Unicode编码表中对应的代码值代码单元:是在计算机中用来表示码点的,大部分码点只需要一个代码单元表示,但是有一些是需要两个代码单元表示的。
不同码点对应的代码单元数量可能不同
下面实际操作体验一番
" " 这个数学符号码点 为U+1D546 在 Java中的代码单元为 U+D835 和U+DD46
String word = "uD835uDD46";
System.out.println("字符为:"+word + " String.length(): "+ word.length());
打印结果如下(String.length()返回的是字符串代码单元的长度)。
字符为: String.length(): 2
而且char类型无法放下这个符号
//char c = ' ';
String word2 = " ";
String firstUnit = Integer.toHexString(word.charAt(0));
String secondUnit = Integer.toHexString(word.charAt(1));
String codePoint = Integer.toHexString(word2.codePointAt(0));
System.out.println("第一个单元:" + firstUnit + " 第二个:" + secondUnit + " 码点:" +codePoint);
打印结果
第一个单元:d835 第二个:dd46 码点:1d546
二、UTF-16编码方式
我们来思考UTF-16的设计思路:
我们知道Unicode的范围为0x0~0x10FFFF
首先是0x0~0xFFFF这段区间,正好16位就可以表示,也兼容,两全其美
那么超过这个区间的怎么办呢?
也就是0xFFFF~0x10FFFF这段,我们先看这段区间有多少个码位,
0x10FFFF-0xFFFF=0x100000,那么这个十六进制表示的十进制也就是:1048576个码位
我们既然16位存不下,那肯定就是32位存咯,这个32能理解为什么不?不理解?是因为计算机只能以2的倍数拓展,如果不这么设计,就没办法解析。长短不一,不符合设计思路
32位来存这些数字,那么我们需要怎么存下呢,简单的思考过后,大家认为应该分开存储,也就是将32位分开前16位和后16位,每个16位各存一半
那么每一半存的就是1024(由来:1024*1024=1048576),1024代表的是2的10次幂,也就是10位二进制数
这样就知道了,32位二进制数字中,前后16位中各存10位就够用了,但是剩余的6位用来干什么呢?
和UTF-8的设计一样,为了让识别字符串变得容易(从文本的任意位置开始,均能区分一个字符的起始),这里是不是有点儿蒙?
举个栗子:
假设:
0000 0001 代表A
0000 0010 代表B
0000 0001 ,0000 0001 代表 X
0000 0010 ,0000 0001 代表Z
那么 ABXZ就是
0000 0001 ,0000 0010 , 0000 0001 ,0000 0001 , 0000 0010,0000 0001
A B X Z
但是让你从中间开始读取,当你读到X的时候,你不知道他是X还是 AB,这样就很麻烦,你需要设置标志,来让16位的数据的前8或后8不会和单个8位的重复
可以这样设计:
0xxx xxxx 代表0~2^7
11xx xxxx ,10xx xxxx 代表其他的
这样就能区分开了,当你读到11开头的,就代表他是16位的前8,10开头代表16位的后8
欧了,有了这个思路,我们就知道怎么设计刚才的那个6位了,当然是通过这6位来区分这16位数字代表的位置
也就是UTF-16中,表示数据有单16位和双16位(32位)两种,那么我们设计成单16位和32位中的前16位和后16位这三个16位完全不会重复,那么我们就能随时读到一组16位,就能知道他是单16还是前16还是后16
举个栗子:
根据上方信息,要求我们通过前6位来区分数据,那么前6位就是2^6=64,也就是开头数字的区间
我们设定如下:
54开头的为32位的前16位
55开头的为32位的后16位
其他开头的为单16位
这样我们就能区分开这三个16位了,在读取文档中的任意位置,都能随意区分出间隔咯
那么54开头的数据区间是多少呢,就是1101 10xx xxxx xxxx,区间就是D800~DBFF
那么55开头的数据区间是多少呢,就是1101 11xx xxxx xxxx,区间就是DC00~DFFF
为了配合UTF-16,Unicode中也将这两个区间屏蔽掉,不允许分配任何字符
下方为比较官方的关于UTF-16的编码详解
参考文献:
具体编码方式
Unicode范围U+10000~U+10FFFF:将Unicode值减去(0x10000),得到20bit长的值。再将Unicode分为高10位和低10位。UTF-16编码的高位是2 Byte,高10位Unicode范围为0-0x3FF,将Unicode值加上0XD800,得到高位代理(或称为前导代理,存储高位);低位也是2 Byte,低十位Unicode范围一样为0~0x3FF,将Unicode值加上0xDC00,得到低位代理(或称为后尾代理,存储低位)
根据上面的转换方式,我们就能够将Unicode码根据UTF-16的编码方式进行转换。下面我们仍然通过两个例子来看下:
U+0020,这个值的范围在第一部分,即经过UTF-16编码后,结果仍然为U+0020,在内存中的顺序为00 20。
U+12345, 这个值的范围在第二部分,因此需要先减去0x10000,得到0x02345,拆分成高10位00 0000 1000和低10位11 0100 0101。根据上面规则加上特定值后,高位代理值为D808,低位代理值为DF45,最终内存中的顺序为D8 08 DF 45。
结果是3 108
offsetByCodePoints(1,2);//返回从1处开始的第2个Code Point的位置
代码点(codepoint):是指与一个编码表中的某个字符对应的代码值。
也就是从下标1开始的第2个代码点的位置,那不就是3么.
codePointAt(index); //获取第index位置的Code Point.返回类型是对应字符的ascii.
那就是获取第3位的代码点也就是l.而l对应的ascii码就是108