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

时间:2011-05-05 19:21:58

标签: java unicode utf-16 surrogate-pairs

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

6 个答案:

答案 0 :(得分:114)

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

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

在内部,Java使用UTF-16编码方案来存储Unicode文本的字符串。在UTF-16中,使用16位(双字节)代码单元。由于16位只能包含从0x0到0xFFFF的字符范围,因此使用一些额外的复杂度来存储高于此范围(0x10000到0x10FFFF)的值。这是使用称为代理的代码单元对完成的。

代理代码单元分为两个范围,称为“高代理”和“低代理”,具体取决于它们是否允许在双代码单元序列的开头或结尾。

答案 1 :(得分:22)

该文档所说的是,无效的UTF-16字符串在调用reverse方法后可能会生效,因为它们可能是有效字符串的反转。代理对(讨论here)是UTF-16中的一对16位值,它们编码单个Unicode代码点;低和高代理是编码的两半。

答案 2 :(得分:6)

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

答案 3 :(得分:6)

this帖子中为上述答案添加更多信息

在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 number of Unicode character in Java String  

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

"".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.Collator对字符串进行排序
7.不应使用字符toUppercase,小写字母,而应使用String的大写字母和特定语言环境的小写字母
8. Character.isLetter(char ch)不支持,最好使用Character.isLetter(int codePoint),对于Character类中的每个methodName(char ch)方法,将有methodName(int codePoint)类型,可以处理补充字符。
9.在String.getBytes()中指定字符集,从字节转换为字符串,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

示例image1 image2的更多信息
其他值得探讨的术语:NormalizationBiDi

答案 4 :(得分:3)

代理对是UTF-16中的两个“代码单元”,构成一个“代码点”。 Java文档说明这些“代码点”仍然有效,反向后它们的“代码单元”正确排序。它进一步指出两个不成对的代理代码单元可以被颠倒并形成有效的代理对。这意味着如果有不成对的代码单元,那么反向的反转可能不一样!

请注意,文档中没有提到Graphemes - 这是多个代码点的组合。这意味着e和伴随它的重音仍然可以切换,从而在e之前放置重音。这意味着如果在e之前有另一个元音,它可能会获得e上的重音。

糟糕!

答案 5 :(得分:3)

小序言

  • Unicode代表代码点。每个代码点都可以根据Unicode标准以8位,16位或32位块进行编码。
  • 在版本3.1之前,使用最多的是8位编码(称为UTF-8)和16位编码(称为UCS-2或“以2个八位位组编码的通用字符集”)。 UTF-8将Unicode点编码为1字节的块序列,而UCS-2始终占用2字节:

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

问题

该联合会认为16位就足以覆盖任何人类可读的语言,这给了 2 ^ 16 = 65536 可能的代码值。对于“平面0”(也称为BPM或“基本多语言平面”)而言,这是正确的,它今天包含55,445个65536个代码点。 BPM涵盖了世界上几乎所有人类语言,包括中日韩符号(CJK)。

时间的流逝,并添加了新的亚洲字符集,仅中国符号一项就花费了超过70,000点。现在,甚至还有Emoji points作为标准part的一部分。添加了新的16个“附加” Planes。 UCS-2的房间不足以覆盖比Plane-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 + D800–U + DBFF,称为“高替代”;将1024个符号U + DC00–U + DFFF(称为低代理)分配给UTF-16。

    有了这些更改,BPM在UTF-16中被1个16位的块所覆盖,而所有“补充字符”都被代理对所覆盖,它们分别显示2个块,每个16位,总共1024x1024 = 1 048 576点。

    高替代物先于低替代物。与此规则的任何偏差都被认为是错误的编码。例如,没有一对的代理人是不正确的,而高代理人之前的低代理人身份是不正确的。

    ?,“音乐符号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。
  • 代理解决方案打开了许多security problems,以在不同编码之间进行转换,其中大多数都处理得很好。

许多历史细节都被禁止遵循主题<。
最新的Unicode标准可在http://www.unicode.org/versions/latest

中找到