Java 中的“代理对”是什么?

我正在阅读 StringBuffer的文档,特别是 反向()方法。该文档提到了关于 代理人配对的一些内容。在这种情况下,什么是代理对?什么是 很高代理?

78753 次浏览

代理项对指的是 UTF-16对特定字符进行编码的方式,请参见 http://en.wikipedia.org/wiki/UTF-16/UCS-2#Code_points_U.2B10000..U.2B10FFFF

文档的意思是,无效的 UTF-16字符串在调用 reverse方法之后可能会变成有效的,因为它们可能是有效字符串的反面。代理对(我们讨论过 给你)是 UTF-16中一对编码单个 Unicode字符的16位值,低代理和高代理是编码的两部分。

术语“代理对”是指在 UTF-16编码模式中使用高编码点对 Unicode 字符进行编码的方法。

在 Unicode 字符编码中,字符被映射到0x0到0x10FFFF 之间的值。

在内部,Java 使用 UTF-16编码模式来存储 Unicode 文本的字符串。在 UTF-16中,使用16位(两字节)代码单元。由于16位只能包含从0x0到0xFFFF 的字符范围,所以使用一些额外的复杂性来存储这个范围(0x10000到0x10FFFF)以上的值。这是通过使用称为代理的代码单元对来完成的。

代理代码单元在两个范围内,即“高代理”和“低代理”,这取决于在两个代码单元序列的开始或结束处是否允许它们。

代理对是 UTF-16中的两个“代码单元”,组成一个“代码点”。Java 文档声明这些“代码点”仍然有效,它们的“代码单元”在反过来之后排序正确。它进一步指出,两个不成对的代理代码单元可以相反,并形成一个有效的代理代理对。这意味着,如果有不成对的代码单位,那么有一个机会,反向可能是不一样的!

但是请注意,文档中没有提到 Graphemes ——它是多个代码点的组合。这意味着 e 和随之而来的重音仍然可能被转换,因此把重音放在 e 之前,这意味着如果在 e 之前有另一个元音,它可能会得到 e 上的重音。

哎呀!

早期的 Java 版本使用16位字符数据类型表示 Unicode 字符。这种设计在当时是有意义的,因为所有 Unicode 字符的值都小于65,535(0xFFFF) ,并且可以用16位来表示。但是,后来 Unicode 将最大值增加到1,114,111(0x10FFFF)。由于16位值太小,无法表示 Unicode 3.1版中的所有 Unicode 字符,因此 UTF-32编码方案采用了32位值(称为编码点)。 但是为了有效地使用内存,16位值比32位值更受欢迎,因此 Unicode 引入了一种新的设计,允许继续使用16位值。这种设计采用了 UTF-16编码方案,将1024个值分配给16位高代理(U + D800到 U + DBFF) ,另外1024个值分配给16位低代理(U + D00到 U + DFFF)。它使用一个高代理项后跟一个低代理项ーー一个代理项对ーー来表示65,536(0x10000)和1,114,111(0x10FFFF)之间的(1,024和1,024的乘积)1,048,576(0x100000)值。

这个帖子中为上面的答案添加一些更多的信息。

经过 Java-12测试,应该可以在5以上的所有 Java 版本中工作。

正如这里提到的: https://stackoverflow.com/a/47505451/2987755,
任何一个字符(其 Unicode 高于 U + FFFF)表示为代理对,Java 将其存储为一对 char 值,即单个 Unicode字符表示为两个相邻的 Java 字符。
正如我们在下面的例子中看到的。
1. 长度:

"🌉".length()  //2, Expectations was it should return 1


"🌉".codePointCount(0,"🌉".length())  //1, To get the number of Unicode characters in a Java String

2. 平等:
使用 Unicode \ud83c\udf09将“”表示为 String,并检查是否相等。

"🌉".equals("\ud83c\udf09") // true

Java 不支持 UTF-32

"🌉".equals("\u1F309") // false

你可以把 Unicode字符转换成 Java 字符串

"🌉".equals(new String(Character.toChars(0x0001F309))) //true

Substring ()不考虑补充字符

"🌉🌐".substring(0,1) //"?"
"🌉🌐".substring(0,2) //"🌉"
"🌉🌐".substring(0,4) //"🌉🌐"

为了解决这个问题,我们可以使用 String.offsetByCodePoints(int index, int codePointOffset)

"🌉🌐".substring(0,"🌉🌐".offsetByCodePoints(0,1) // "🌉"
"🌉🌐".substring(2,"🌉🌐".offsetByCodePoints(1,2)) // "🌐"

5. 使用 断路器迭代 Unicode 字符串
6. 使用 Unicode 对字符串进行排序
7. 不应使用字符的 toUpperCase()toLowerCase()方法,而应使用特定语言环境的字符串大小写。
8.Character.isLetter(char ch)不支持,更好地使用 Character.isLetter(int codePoint),对于每个 methodName(char ch)方法在字符类将有类型的 methodName(int codePoint),可以处理补充字符。
String.getBytes()中指定字符集,从 Bytes 转换为 String,InputStreamReaderOutputStreamWriter

参考:
Https://coolsymbol.com/emojis/emoji-for-copy-and-paste.html#objects
Https://www.online-toolz.com/tools/text-unicode-entities-convertor.php
Https://www.ibm.com/developerworks/library/j-unicode/index.html
Https://www.oracle.com/technetwork/articles/javaee/supplementary-142654.html

更多关于示例 图1 图2的信息
其他值得探索的术语: 正常化,< a href = “ https://en.wikipedia.org/wiki/Bi-direct _ text”rel = “ noReferrer”> BiDi

小小的序言

  • Unicode 表示代码点。根据 Unicode 标准,每个代码点可以编码为8位、16位或32位块。

  • 在 Version 3.1之前,主要使用的是8位编码(称为 UTF-8)和16位编码(称为 UCS-2或“通用字符集以2个八位字节编码”)。UTF-8将 Unicode 点编码为一个1字节的块序列,而 UCS-2总是占用2字节:

    A = 41 -一个带有 UTF-8的8位块
    A = 0041 -一个带 UCS-2的16位块
    Ω = CEA9 -两个带 UTF-8的8位块
    Ω = 03A9 -一个带 UCS-2的16位块

问题

该联盟认为,16位将足以涵盖任何人类可读的语言,这使得 2 ^ 16 = 65536可能的代码值。这是真正的平面0,也称为 BMP 或基本多语言平面,其中包括55,445的65536个代码点今天。BMP 几乎涵盖了世界上所有的人类语言,包括中日韩符号(CJK)。

随着时间的推移,新的亚洲字符集被添加进来,仅中文符号就占据了超过70,000分。现在,甚至有 表情符号点数作为标准的一部分。新增16个“额外”飞机。UCS-2房间不足以覆盖任何比飞机 -0大的东西。

Unicode 决定

  1. 将 Unicode 限制为每个平面的17个平面 × 65536个字符 = 1114112个最大点。
  2. 目前的 UTF-32,以前称为 UCS-4,为每个编码点保持32位并覆盖所有平面。
  3. 继续使用 UTF-8作为动态编码,将每个编码点的 UTF-8最大限制为4个字节,即每个编码点从1到4个字节。
  4. 废除 UCS-2
  5. 基于 UCS-2创建 UTF-16。使 UTF-16是动态的,因此每个点占用2字节或4字节。给 UTF-16分配1024个 U + D 800-U + DBFF,称为高代理人; 给 UTF-16分配1024个符号 U + DC 00-U + DFFF,称为低代理人。

随着这些变化,BMP 在 UTF-16中被覆盖了1个16位的块,而所有的“补充字符”都被 代理机器人覆盖,每个 代理机器人呈现2个16位的块,总共1024x1024 = 1048576点。

高代理项优先于低代理项 。任何偏离此规则的行为都被认为是错误的编码。例如,没有对的代理项是不正确的,位于高代理项之前的低代理项是不正确的。

,‘ MUSAL SYMBOL G CLEF’,以 UTF-16编码,作为一对代理人0xD8340xDD1E (2乘2字节) ,
0xF00x9D 0x840x9E (4 × 1字节) ,
以 UTF-32为0x0001D11E (1乘4字节)。

目前的情况

  • 虽然根据标准,代理只被指定给 UTF-16,但是历史上一些 Windows 和 Java 应用程序使用 UTF-8和 UCS-2点,现在保留给代理范围。
    为了支持使用不正确的 UTF-8/UTF-16编码的遗留应用程序,创建了一个新的标准 WTF-8,即 WobblyTransformationFormat。它支持任意的代理点,比如不成对的代理点或不正确的序列。今天,一些产品不符合标准,把 UTF-8视为 WTF-8。
  • 代理解决方案打开了一些 安全问题,并尝试使用“非法代理对”。

许多历史细节都被压制下去了。
最新的 Unicode 标准可以在 < a href = “ http://www.Unicode.org/version/last”rel = “ norefrer”> http://www.Unicode.org/versions/latest 找到