我试图找到对“字符”,“代码点”和“代理”这两个术语的解释,虽然这些术语不仅限于Java,但如果存在任何语言特定的差异,我会喜欢与Java有关的解释。
我发现了一些关于字符和代码点之间差异的信息,字符是为人类用户显示的内容,代码点是编码该特定字符的值,但我对代理人一无所知。什么是代理人,他们与角色和代码点有什么不同?我是否对字符和代码点有正确的定义?
在another thread中关于将字符串作为字符数组逐步执行,提示此问题的具体注释是“请注意,此技术为您提供字符,而不是代码点,这意味着您可能会获得代理。”我真的不明白,而不是就一个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值的无符号双字节值。
答案 1 :(得分:13)
您可以在Javadoc中找到类java.lang.Character的简短说明:
Unicode字符表示
char
数据类型(以及Character
对象封装的值)基于原始Unicode规范,该规范将字符定义为固定宽度的16位实体。此后,Unicode标准已更改为允许表示形式需要16位以上的字符。合法代码点的范围现在为U+0000
到U+10FFFF
,称为 Unicode标量值。 [..]
U+0000
到U+FFFF
的字符集有时也称为基本多语言平面(BMP)。代码点大于U+FFFF
的字符称为补充字符。 Java平台使用char
数组和String
和StringBuffer
类中的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有很长的编号字符列表,其中代码点指的是编号。
简而言之
UTF-16
编码方案表示的字符包含许多字符,这些字符都不适合单个java字符的alotted空间。 答案 4 :(得分:1)
简单地说:
Code unit
是char
,占用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个代码单元时,它们不能识别,并分别显示?
。