Java如何在其16位字符类型中存储UTF-16字符?

Kie*_*row 23 java variables unicode encoding utf-16

根据Java SE 7规范,Java使用Unicode UTF-16标准来表示字符.当想象一个String作为简单阵列 16位变量中的每个包含一个字符,寿命也很简单.

不幸的是,有16位的代码点是不够的(我相信它是所有Unicode字符的16/17).所以在a中String,这没有直接问题,因为当想要使用额外的两个字节存储这些~1.048.576个字符中的一个时,String将仅使用其中的两个数组位置.

这没有任何直接问题,适用于Strings,因为总有一个额外的两个字节.虽然单变量与UTF-16编码相比,具有16位固定长度,但是如何存储这些字符,特别是Java如何使用其2字节"char"来完成类型

Den*_*ret 25

答案在javadoc中:

char数据类型(以及Character对象封装的值)基于原始Unicode规范,该规范将字符定义为固定宽度的16位实体.此后,Unicode标准已更改为允许表示形式需要16位以上的字符.

合法代码点的范围现在是U + 0000到U + 10FFFF,称为Unicode标量值.(请参阅Unicode标准中U + n表示法的定义.)U + 0000到U + FFFF的字符集有时称为基本多语言平面(BMP).代码点大于U + FFFF的字符称为增补字符.Java 2平台在char数组和String和StringBuffer类中使用UTF-16表示.在此表示中,补充字符表示为一对char值,第一个来自高代理范围(\ uD800-\uDBFF),第二个来自低代理范围(\ uDC00-\uDFFF).

因此,char值表示基本多语言平面(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代码单元用于16位字符值,这些值是UTF-16编码的代码单元.有关Unicode术语的更多信息,请参阅Unicode术语表.

简单地说:

  • char规则的16位是为旧版本的Unicode标准设计的
  • 你有时需要两个字符来表示一个不在基本多语言平面中的unicode符文(代码点).这种"有效"因为你不经常使用字符,尤其是处理BMP之外的unicode符文.

更简单的说:

  • java char不代表Unicode代码点(嗯,并非总是如此).

顺便说一下,可以注意到Unicode的演变超过了BMP,使得UTF-16在全球范围内无关紧要,因为UTF-16甚至不能实现固定的字节 - 字符比.这就是更多现代语言基于UTF-8的原因.这个宣言有助于理解它.


Jon*_*eet 7

基本上,字符串存储一系列UTF-16代码单元......这与存储一系列Unicode代码点不同.

当需要基本多语言平面之外的字符时,它占用了两个UTF-16代码单元String.

大多数String运营- ,,length() 等交易中的UTF-16编码单元号.但是,有些操作会处理完整的Unicode代码点......尽管索引仍以UTF-16代码单位表示.charAtsubstring()codePointAt()

编辑:如果你想在一个单独存储一个非BMP代码点char,你基本上是运气不好.这就像是想在byte变量中存储超过256个不同的值......它只是不起作用.遵循在其他地方(例如in String)表示代码点的约定,最好只使用int变量.

  • 有趣且重要,但问题似乎更多地集中在个人`char`s而不是字符串操作(参见问题的最后一句). (3认同)