我正在阅读的文档StringBuffer
,尤其是reverse()方法。该文档提到了有关代理对的内容。在这种情况下什么是代理对?什么是低和高的代理人?
String
的代码点,而不仅仅是char单元。太糟糕了,Java不允许您使用OO来解决此问题,但是String
该类和这些StringBuffer
类均已实现final
。说,这不是对被杀害的委婉说法吗?:)
我正在阅读的文档StringBuffer
,尤其是reverse()方法。该文档提到了有关代理对的内容。在这种情况下什么是代理对?什么是低和高的代理人?
String
的代码点,而不仅仅是char单元。太糟糕了,Java不允许您使用OO来解决此问题,但是String
该类和这些StringBuffer
类均已实现final
。说,这不是对被杀害的委婉说法吗?:)
Answers:
术语“代理对”是指以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字符,因此UTF-32编码方案采用了32位值(称为代码点)。但是为了有效使用内存,16位值比32位值更可取,因此Unicode引入了一种新设计,可以继续使用16位值。在UTF-16编码方案中采用的此设计将1,024个值分配给16位低代理(在U + D800至U + DBFF范围内),并将另外1,024个值分配给16位低代理(在U + DC00范围内)到U + DFFF)。
该文档所说的是,无效的UTF-16字符串在调用该reverse
方法后可能变得有效,因为它们可能是有效字符串的反向。代理对(在此处讨论)是UTF-16中的一对16位值,它们对单个Unicode代码点进行编码。低和高替代是该编码的两半。
向该帖子的以上答案中添加更多信息。
经过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
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.迭代Unicode字符串与的BreakIterator
6.排序字符串使用Unicode java.text.Collator中
7.字符的toUpperCase()
,toLowerCase()
,方法不应该被使用,相反,使用字符串大写和特定地点的小写。
8. Character.isLetter(char ch)
不支持,更好地使用Character.isLetter(int codePoint)
,对于methodName(char ch)
Character类中的每个方法,都会有methodName(int codePoint)
可以处理补充字符的类型。
9.在中指定字符集String.getBytes()
,将Bytes转换为String 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编码某些字符的方式,请参见http://en.wikipedia.org/wiki/UTF-16/UCS-2#Code_points_U.2B10000..U.2B10FFFF
小序言
在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位块
= CE A9-带有UTF-
8Ω的两个8位块= 03A9-一个使用UCS-2的16位
问题
该联盟认为16位就足以覆盖任何人类可读的语言,这给了2 ^ 16 = 65536个可能的代码值。对于“平面0”(也称为BPM或“基本多语言平面”)而言,这是正确的,它今天包含55,445个65536个代码点。BPM涵盖了世界上几乎所有人类语言,包括中日韩符号(CJK)。
时间的流逝和新的亚洲字符集的添加,仅中国符号就花费了超过70,000点。现在,甚至在标准😺中都有表情符号点。添加了新的16个“其他” 飞机。UCS-2会议室不足以覆盖比Plane-0更大的空间。
Unicode决定
基于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点。
较高的替代品先于较低的替代品。与此规则的任何偏差都被认为是错误的编码。例如,没有一对的代理人是不正确的,高代理人之前的低代理人身份是不正确的。
𝄞,``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字节)。
现在的情况
许多历史细节被压制以遵循主题⚖。
最新的Unicode标准可在http://www.unicode.org/versions/latest中找到