Java charAt与具有两个代码单元的字符一起使用

Pat*_*ois 13 java unicode utf-16 surrogate-pairs astral-plane

来自Core Java,第一卷.第1版,第9版,p.69:

字符ℤ需要两个UTF-16编码的代码单元.调用

String sentence = "? is the set of integers"; // for clarity; not in book
char ch = sentence.charAt(1)
Run Code Online (Sandbox Code Playgroud)

不返回空格而是返回second的第二个代码单元.

但它似乎sentence.charAt(1) 确实返回了一个空间.例如,if以下代码中的语句求值为true.

String sentence = "? is the set of integers";
if (sentence.charAt(1) == ' ')
    System.out.println("sentence.charAt(1) returns a space");
Run Code Online (Sandbox Code Playgroud)

为什么?

我在Ubuntu 12.10上使用JDK SE 1.7.0_09,如果它是相关的.

Mar*_*sel 8

听起来这本书说'ℤ'不是基本多语言平面中的UTF-16字符,但实际上它是.

Java将UTF-16与代理对一起用于不在基本多语言平面中的字符.由于'ℤ'(0x2124)在基本多语言平面中,因此它由单个代码单元表示.在你的例子sentence.charAt(0)中将返回'ℤ',sentence.charAt(1)并将返回''.

由代理对表示的字符具有构成该字符的两个代码单元.sentence.charAt(0)将返回第一个代码单元,并sentence.charAt(1)返回第二个代码单元.

请参阅http://docs.oracle.com/javase/6/docs/api/java/lang/String.html:

String表示UTF-16格式的字符串,其中补充字符由代理项对表示(有关详细信息,请参阅Character类中的Unicode字符表示形式一节).索引值是指char代码单元,因此补充字符在String中使用两个位置.


Jas*_*ske 7

根据文档,String在内部表示为utf-16,因此charAt()为您提供了两个代码点.如果您有兴趣查看各个代码点,可以使用此代码(来自此答案):

final int length = sentence.length();
for (int offset = 0; offset < length; ) {
   final int codepoint = sentence.codePointAt(offset);

   // do something with the codepoint

   offset += Character.charCount(codepoint);
}
Run Code Online (Sandbox Code Playgroud)

  • "对于每个人来说,两个字节应该足够了" - 比尔·加特斯 (2认同)
  • `charAt()` 给出了一个代码单元,它可以是一个代码点(对于 BMP 字符)或一个代理代码单元,它可能被非正式地描述为“半个代码点”。永远不要有两个代码点。 (2认同)