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

时间:2013-01-04 03:05:11

标签: 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)
     

不返回空格,而是返回第二个代码单元<。

但似乎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");

为什么?

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

4 个答案:

答案 0 :(得分:8)

听起来这本书说'ℤ'不是basic multilingual plane中的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格式的字符串   补充字符由代理对表示(参见   section字符类中的Unicode字符表示形式   更多信息)。索引值是指char代码单元,所以a   补充字符在字符串中使用两个位置。

答案 1 :(得分:7)

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

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);
}

答案 2 :(得分:2)

Javadocs解释一下:

  

String表示UTF-16格式的字符串   补充字符由代理对表示(参见   section字符类中的Unicode字符表示形式   更多信息)。索引值是指char代码单元,所以a   补充字符在字符串中使用两个位置。

总之,这本书是错的。

编辑以添加以下评论:我昨晚没想到的是你在问题中使用的角色实际上并不是他们正在讨论的角色,以及当你拥有一个需要四个字节而不是两个字节的字符时,他们真正得到的就是它们。 Javadoc上面的段落链接到另一个javadoc; Unicode Character Representations讨论了这种情况的后果。

答案 3 :(得分:0)

Horstmann在谈论需要两个UTF-16代码单元的'Z'。 看一下这段代码:

public class Main {
    public static void main(String[] args)
    {
        String a = "\uD83D\uDE02 is String";
        System.out.println("Length: " + a.length());
        System.out.println(a.charAt(0));
        System.out.println(a.charAt(1));
        System.out.println(a.charAt(2));
        System.out.println(a.charAt(3));
    }
}

在IntelliJ Idea中,我什至不能将4字节字符粘贴为一个字符,因为粘贴此表情符号时:IDE会自动将其转换为:“ \ uD83D \ uDE02”。请注意,此表情符号算作2个字符。

如果要计算“实际长度”,则应使用: System.out.println("Real length: " + a.codePointCount(0, a.length()));

看看:What are the most common non-BMP Unicode characters in actual use?