Java - 什么是字符,代码点和代理?他们之间有什么区别?

时间:2014-06-01 12:06:17

标签: java character-encoding character

我试图找到对“字符”,“代码点”和“代理”这两个术语的解释,虽然这些术语不仅限于Java,但如果存在任何语言特定的差异,我会喜欢与Java有关的解释。

我发现了一些关于字符和代码点之间差异的信息,字符是为人类用户显示的内容,代码点是编码该特定字符的值,但我对代理人一无所知。什么是代理人,他们与角色和代码点有什么不同?我是否对字符和代码点有正确的定义?

another thread中关于将字符串作为字符数组逐步执行,提示此问题的具体注释是“请注意,此技术为您提供字符,而不是代码点,这意味着您可能会获得代理。”我真的不明白,而不是就一个5年前的问题创建一系列评论,我认为最好在新问题中要求澄清。

5 个答案:

答案 0 :(得分:20)

要在计算机中表示文本,您必须解决两件事:首先,您必须将符号映射到数字,然后,您必须用字节表示这些数字的序列。

Code point是标识符号的数字。为符号分配数字的两个众所周知的标准是ASCII和Unicode。 ASCII定义128个符号。 Unicode目前定义了109384个符号,超过2个 16

此外,ASCII指定数字序列表示每个数字一个字节,而Unicode指定几种可能性,例如UTF-8,UTF-16和UTF-32。

当您尝试使用每个字符使用少于表示所有可能值(例如UTF-16,使用16位)所需的位数的编码时,您需要一些解决方法。

因此,Surrogates是16位值,表示不符合单个双字节值的符号。

Java使用UTF-16。

特别是,char(字符)是一个包含UTF-16值的无符号双字节值。

如果您想了解有关Java和Unicode的更多信息,我可以推荐此简报:Part 1Part 2

答案 1 :(得分:13)

您可以在Javadoc中找到类java.lang.Character的简短说明:

  

Unicode字符表示

     

char数据类型(以及Character对象封装的值)基于原始Unicode规范,该规范将字符定义为固定宽度的16位实体。此后,Unicode标准已更改为允许表示形式需要16位以上的字符。合法代码点的范围现在为U+0000U+10FFFF,称为 Unicode标量值。 [..]

     

U+0000U+FFFF的字符集有时也称为基本多语言平面(BMP)。代码点大于U+FFFF的字符称为补充字符。 Java平台使用char数组和StringStringBuffer类中的UTF-16表示。在此表示中,补充字符表示为一对char值,第一个来自高代理范围,(\ uD800- \ uDBFF),第二个来自低代理范围(\ uDC00- \ uDFFF)。

换句话说:

代码点通常代表一个字符。最初,类型char的值与Unicode代码点完全匹配。此编码也称为UCS-2

因此,char被定义为16位类型。但是,Unicode中目前有超过2 ^ 16个字符。为了支持整个字符集,编码从固定长度编码UCS-2更改为可变长度编码UTF-16。在此编码中,每个代码点由单个char或两个char表示。在后一种情况下,两个字符称为代理对

UTF-16以这样的方式定义,如果所有代码点都低于2 ^ 14,则使用UTF-16和UCS-2编码的文本之间没有区别。这意味着,char可用于表示一些但不是所有字符。如果字符无法在单个char中表示,则术语char会产生误导,因为它只是用作16位字。

答案 2 :(得分:7)

代码点通常是指Unicode代码点。 Unicode术语表说:

  

Codepoint(1):Unicode代码空间中的任何值;也就是说,从0到10FFFF16的整数范围。

在Java中,字符(char)是无符号的16位值;即0到FFFF。

如您所见,有更多Unicode代码点可以表示为Java字符。然而,Java需要能够使用所有有效的Unicode代码点来表示文本。

Java处理此问题的方法是将大于FFFF的代码点表示为字符(代码单元);即surrogate pair。这些编码一个大于FFFF的Unicode代码点,作为一对16位值。这使用了以下事实:Unicode代码空间的子范围(即D800到U + DFFF)被保留用于表示代理对。技术细节为here


Java正在使用的编码的正确术语是UTF-16 Encoding Form

您可能会看到的另一个术语是code unit,它是特定编码中使用的最小代表单位。在UTF-16中,代码单元是16位,对应于Java char。其他编码(例如UTF-8,ISO 8859-1等)具有8位代码单元,UTF-32具有32位代码单元。


角色这个词有很多含义。它意味着不同背景下的各种事物。 Unicode术语表为Character提供了4个含义,如下所示:

  

字符。 (1)具有语义价值的书面语言的最小组成部分;指的是抽象的意义和/或形状,而不是特定的形状(参见字形),但在代码表中,某种形式的视觉表现对于读者的理解是必不可少的。

     

字符。 (2)抽象字符的同义词。 (Abstract Character。用于组织,控制或表示文本数据的信息单元。)

     

字符。 (3)Unicode字符编码的基本编码单位。

     

字符。 (4)中国出身的表意文字要素的英文名称。 [见表意文字(2)。]

然后是字符的Java特定含义。

答案 3 :(得分:5)

首先,unicode是一个标准,它试图定义和映射所有语言的所有单个字符,从英文字母到中文,数字,符号等。

基本上unicode有很长的编号字符列表,其中代码点指的是编号。

简而言之

  • 字符是文本中的单个标记,无论是字母,数字还是符号。
  • 代码点是指unicode标准中令牌的编号
  • 使用UTF-16编码方案表示的字符包含许多字符,这些字符都不适合单个java字符的alotted空间。
  • Surrogate pairs用于表示一个字符需要在一对字符的空格中表示。 代理对是一个术语,用于表示在unicode表中列出如此高的一个字符,它需要一对字符空间来表示它。

答案 4 :(得分:1)

简单地说:

  • Code unitchar,占用2个字节,编码为UTF-16,每个字符不一定代表real world character
  • Code point始终是real world character,它可能包含1或2个Code unit,将其视为int,可能需要4个字节。

让代码(测试用例)说实话:
(由于String的方法codePoints()chars(),因此需要Java 9 +)

@Test
public void test() {
    String s = "Hi, 你好, おはよう, α-Ω\uD834\uDD1E"; // last real character is "?", that takes 2 code unit,
    assertEquals(s.length(), s.toCharArray().length); // length() is based on char (aka code unit), not code point,

    System.out.printf("input string:\t\"%s\"%n%n", s);

    System.out.println("------ as code point (aka. real character) ------");
    // code point,
    s.codePoints().forEach(cp -> System.out.println(Character.toChars(cp)));
    assertEquals(s.codePoints().count(), s.length() - 1); // last read character takes 2 unit code,
    assertEquals(s.codePoints().count(), s.codePointCount(0, s.length())); // there is a method codePointCount() on String to get code point count on given char range,

    System.out.println("\n------ as char (aka. code unit) ------");
    // chars (aka. code unit),
    s.chars().forEach(c -> System.out.println(Character.toChars(c)));
    assertEquals(s.chars().count(), s.length()); // string length is the count of code unit, not code point,
}

输出:

input string:   "Hi, 你好, おはよう, α-Ω?"

------ as code point (aka. real character) ------
H
i
,
 
你
好
,
 
お
は
よ
う
,
 
α
-
Ω
?

------ as char (aka. code unit) ------
H
i
,
 
你
好
,
 
お
は
よ
う
,
 
α
-
Ω
?
?

最后一个实字符是?,它需要2个代码单元\uD834\uDD1E,并且是单个code point,当尝试分别打印2个代码单元时,它们不能识别,并分别显示?