我正在阅读文档StringBuffer
,特别是reverse()方法。该文档提到了一些关于代理对的内容。在这种情况下,什么是代理对?什么是低代理和高代理?
7 回答
术语“代理对”是指在 UTF-16 编码方案中对具有高代码点的 Unicode 字符进行编码的方法。
在 Unicode 字符编码中,字符被映射到 0x0 和 0x10FFFF 之间的值。
在内部,Java 使用 UTF-16 编码方案来存储 Unicode 文本字符串。在 UTF-16 中,使用 16 位(两字节)代码单元。由于 16 位只能包含从 0x0 到 0xFFFF 的字符范围,因此会使用一些额外的复杂性来存储高于此范围(0x10000 到 0x10FFFF)的值。这是使用称为代理的代码单元对完成的。
代理代码单元在称为“高代理”和“低代理”的两个范围内,这取决于它们在两个代码单元序列的开头还是结尾被允许。
早期的 Java 版本使用 16 位 char 数据类型表示 Unicode 字符。这种设计在当时是有意义的,因为所有 Unicode 字符的值都小于 65,535 (0xFFFF),并且可以用 16 位表示。然而,后来,Unicode 将最大值增加到 1,114,111 (0x10FFFF)。由于 16 位值太小,无法表示 Unicode 版本 3.1 中的所有 Unicode 字符,因此 32 位值(称为代码点)被用于 UTF-32 编码方案。但是为了有效地使用内存,16 位值优于 32 位值,因此 Unicode 引入了一种新设计以允许继续使用 16 位值。该设计采用 UTF-16 编码方案,将 1,024 个值分配给 16 位高代理项(在 U+D800 到 U+DBFF 范围内),将另外 1,024 个值分配给 16 位低代理项(在 U+DC00 范围内)到 U+DFFF)。
从这篇文章中为上述答案添加更多信息。
在 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
,如下所示并检查相等性。
"".equals("\ud83c\udf09") // true
Java 不支持 UTF-32
"".equals("\u1F309") // false
3.您可以将Unicode字符转换为Java字符串
"".equals(new String(Character.toChars(0x0001F309))) //true
4. String.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. 使用BreakIterator迭代 Unicode 字符串6. 使用 Unicode java.text.Collat
or
对字符串进行排序
7.不应使用字符的, , 方法,而是使用特定语言环境的大写和小写字符串。
8.不支持,更好用, Character类中的每个方法都会有可以处理增补字符的type。
9. 指定字符集,从字节转换为字符串,,toUpperCase()
toLowerCase()
Character.isLetter(char ch)
Character.isLetter(int codePoint)
methodName(char ch)
methodName(int codePoint)
String.getBytes()
InputStreamReader
OutputStreamWriter
参考:
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
有关示例image1 image2的更多信息
其他值得探索的术语:Normalization , BiDi
该文档所说的是无效的 UTF-16 字符串在调用该reverse
方法后可能会变得有效,因为它们可能是有效字符串的反转。代理对(在此处讨论)是 UTF-16 中的一对 16 位值,它们编码单个 Unicode 代码点;低代理和高代理是该编码的两半。
小序言
Unicode 表示代码点。根据 Unicode 标准,每个代码点都可以编码为 8 位、16 位或 32 位块。
在 3.1 版之前,主要使用的是 8 位编码,称为 UTF-8,和 16 位编码,称为 UCS-2 或“用 2 个八位字节编码的通用字符集”。UTF-8 将 Unicode 点编码为 1 字节块的序列,而 UCS-2 总是占用 2 个字节:
A = 41 - 一个 8 位块,UTF-8
A = 0041 - 一个 16 位块,UCS-2
Ω = CE A9 - 两个 8 位块,UTF-8
Ω = 03A9 - 一个块16 位,带 UCS-2
问题
该联盟认为 16 位足以涵盖任何人类可读的语言,这提供了2^16 = 65536 个可能的代码值。对于今天的 65536 个代码点中的 55,445 个平面 0,也称为 BMP 或基本多语言平面,情况就是如此。BMP 涵盖了世界上几乎所有人类语言,包括中日韩符号 (CJK)。
时光荏苒,添加了新的亚洲字符集,仅中文符号就占了 70,000 多分。现在,甚至还有表情符号点作为标准的一部分。添加了新的 16 个“附加”飞机。UCS-2 房间不足以覆盖比 Plane-0 更大的东西。
Unicode 决定
- 将 Unicode 限制为 17 个平面 × 每个平面 65 536 个字符 = 1 114 112 个最大点。
- 呈现 UTF-32,以前称为 UCS-4,为每个代码点保存 32 位并覆盖所有平面。
- 继续使用 UTF-8 作为动态编码,将 UTF-8 限制为每个代码点最多 4 个字节,即每个点从 1 到 4 个字节。
- 弃用 UCS-2
- 基于 UCS-2 创建 UTF-16。使 UTF-16 动态化,因此每点占用 2 个字节或 4 个字节。将 1024 个点 U+D800–U+DBFF,称为 High Surrogates,分配给 UTF-16;将 1024 个符号 U+DC00–U+DFFF,称为低代理,分配给 UTF-16。
通过这些更改,BMP 被 UTF-16 中的 1 个 16 位块覆盖,而所有“补充字符”都被代理对覆盖,每个代理对呈现 2 个块,每个块 16 位,总共 1024x1024 = 1 048 576 点。
高代理在低代理之前。任何与此规则的偏差都被视为错误编码。例如,没有对的代理是不正确的,低代理站在高代理之前是不正确的。
, 'MUSICAL SYMBOL G CLEF', 在 UTF-16 中编码为一对代理项 0xD834 0xDD1E(2 x 2 字节),
在 UTF-8 中为 0xF0 0x9D 0x84 0x9E(4 x 1 字节),
在 UTF-32 中为 0x0001D11E (1 x 4 字节)。
现在的情况
- 尽管根据标准,代理项仅专门分配给 UTF-16,但历史上一些 Windows 和 Java 应用程序使用现在保留给代理项范围的 UTF-8 和 UCS-2 点。
为了支持具有不正确 UTF-8/UTF-16 编码的旧版应用程序,创建了一个新的标准 WTF-8,即摆动转换格式。它支持任意代理点,例如非配对代理或不正确的序列。如今,有些产品不符合标准,将 UTF-8 视为 WTF-8。 - 代理解决方案引发了一些安全问题,以及尝试使用“非法代理对”。
许多历史细节被压制以跟随主题⚖。
最新的 Unicode 标准可以在http://www.unicode.org/versions/latest找到
代理对是指 UTF-16 编码某些字符的方式,请参阅http://en.wikipedia.org/wiki/UTF-16/UCS-2#Code_points_U.2B10000..U.2B10FFFF
代理对是 UTF-16 中的两个“代码单元”,它们构成一个“代码点”。Java 文档声明这些“代码点”仍然有效,它们的“代码单元”顺序正确,反之亦然。它进一步指出,两个未配对的代理代码单元可以反转并形成有效的代理对。这意味着如果存在未配对的代码单元,那么反向的反转可能不一样!
但是请注意,文档中没有提到 Graphemes——它是多个代码点的组合。这意味着 e 和伴随它的重音仍然可以切换,因此将重音放在 e 之前。这意味着如果在 e 之前有另一个元音,它可能会得到 e 上的重音。
哎呀!