繁体   English   中英

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

[英]Java - what are characters, code points and surrogates? What difference is there between them?

我试图找到术语“字符”、“代码点”和“代理”的解释,虽然这些术语不限于 Java,但如果有任何特定于语言的差异,我希望解释为它与Java有关。

我发现了一些关于字符和代码点之间差异的信息,字符是向人类用户显示的内容,代码点是对特定字符进行编码的值,但我不知道代理。 什么是代理,它们与字符和代码点有何不同? 我对字符和代码点有正确的定义吗?

另一个关于将字符串作为字符数组单步执行的帖子中,提示这个问题的具体评论是“请注意,此技术为您提供字符,而不是代码点,这意味着您可能会获得代理。” 我真的不明白,与其对一个 5 年前的问题发表一长串评论,我认为最好在一个新问题中要求澄清。

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

代码点是标识符号的数字。 为符号分配数字的两个众所周知的标准是 ASCII 和 Unicode。 ASCII 定义了 128 个符号。 Unicode 目前定义了 109384 个符号,比 2 16多得多。

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

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

因此, 代理项是 16 位值,表示不适合单个两字节值的符号。

Java 在内部使用UTF-16来表示文本。

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

如果您想了解有关 Java 和 Unicode 的更多信息,我可以推荐此时事通讯:第 1部分第 2 部分

您可以在 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值,第一个来自高代理范围 (\?-\?),第二个来自低代理范围 (\?-\?)。

换句话说:

代码点通常表示单个字符 最初, 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 位字。

代码点通常是指 Unicode 代码点。 Unicode 词汇表是这样说的:

Codepoint(1) : Unicode 代码空间中的任何值; 即 0 到 10FFFF16 的整数范围。

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

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

Java 处理这种情况的方法是将大于 FFFF 的代码点表示为一字符(代码单元); 代理对 这些编码一个Unicode编码点比FFFF较大为一对16位值。 这使用了 Unicode 代码空间的子范围(即 D800 到 U+DFFF)保留用于表示代理对的事实。 技术细节在这里


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

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


字符这个词有很多含义。 这意味着在不同的上下文中的各种事物。 Unicode 词汇表给出了Character 的4 种含义,如下所示:

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

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

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

特点。 (4) 源自中国的表意文字的英文名称。 [见表意文字 (2)。]

然后是字符的Java特定含义; 即一个 16 位有符号数( char类型),它可能代表也可能不代表 UTF-16 编码中的完整或部分 Unicode 代码点。

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

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

简而言之

  • 字符是文本中的单个标记,无论是字母、数字还是符号。
  • 代码点是指 unicode 标准中令牌的编号
  • 使用UTF-16编码方案表示的字符包含如此多的字符,所有字符都无法放入单个 Java 字符的分配空间中。
  • 代理对是用来表示一个字符需要在一对字符的空间中表示的术语。 代理对是一个术语,用来表示一个字符在 unicode 表中列得太高,需要一对字符空格来表示它。

简单的说:

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

让代码(测试用例)说出真相:
(需要 Java 9 +,由于 String 的方法codePoints()chars()

@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 个代码单元\?\? ,它是一个单一的code point ,当尝试分别打印 2 个代码单元时,它们无法识别,并显示? 对于每个。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM