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

     2023-02-24     142

关键词:

【中文标题】什么是 Java 中的“代理对”?【英文标题】:What is a "surrogate pair" in Java? 【发布时间】:2011-08-19 16:02:29 【问题描述】:

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

【问题讨论】:

这是 UTF-16 术语,在此解释:download.oracle.com/javase/6/docs/api/java/lang/… 这种方法有问题:它应该反转完整的字符 ᴀᴋᴀ 代码点 - 而不是 将它们分开,ᴀᴋᴀ 代码单元。错误在于,该特定遗留方法仅适用于单个字符单元而不是代码点,这是您 想要 Strings 组成的,而不仅仅是字符单元。太糟糕了,Java 不允许您使用 OO 来解决这个问题,但 String 类和 StringBuffer 类都已被 final 化。话说,这不是被杀的委婉说法吗? :) @tchrist 文档(和源代码)说它确实反转为一串代码点。 (大概 1.0.2 没有这样做,而且这些天你永远不会有这样的行为改变。) 【参考方案1】:

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

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

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

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

【讨论】:

【参考方案2】:

早期的 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)。它使用高代理后跟低代理(代理对)来表示(1,024 和 1,024 的乘积)1,048,576 (0x100000) 值介于 65,536 (0x10000) 和 1,114,111 (0x10FFFF) 之间。

【讨论】:

我比接受的答案更喜欢这个,因为它解释了 Unicode 3.1 如何从原始 65535 中保留 1024 + 1024(高 + 低)值以获得 1024 * 1024 新值,没有附加要求解析器从字符串的开头开始。 我不喜欢这个暗示 UTF-16 是内存效率最高的 Unicode 编码的答案。 UTF-8 存在,并且 将大多数文本呈现为两个字节。今天主要使用 UTF-16,因为微软在 UTF-32 出现之前就选择了它,而不是为了提高内存效率。您真正想要 UTF-16 的唯一一次是当您在Windows 上进行大量文件处理,因此同时读取 写入它很多.否则,UTF-32 用于高速(b/c 常量偏移)或 UTF-8 用于低内存(b/c 最小 1 字节)【参考方案3】:

在this 帖子的上述答案中添加更多信息。

在 Java-12 中测试,应该适用于 5 以上的所有 Java 版本。

这里提到:https://***.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.Collator 7.不要使用字符的toUpperCase(),toLowerCase(),方法,而是使用特定语言环境的大写和小写字符串。 8.Character.isLetter(char ch)不支持,最好使用Character.isLetter(int codePoint),对于Character类中的每个methodName(char ch)方法,都会有methodName(int codePoint)的类型,可以处理补充字符。 9.在String.getBytes()中指定charset,将Bytes转换为String,InputStreamReaderOutputStreamWriter

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

有关示例的更多信息 image1 image2 其他值得探索的术语:Normalization、BiDi

【讨论】:

【参考方案4】:

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

【讨论】:

澄清。字符串必须在“真”字符(也称为“字形”或“文本元素”)上反转。单个“字符”代码点可以是一个或两个“字符”块(代理对),而字素可以是这些代码点中的一个或多个(即基本字符代码加上一个或多个组合字符代码,每个可以是一个或两个 16 位块或“字符”长)。因此,单个字素可以是三个组合字符,每两个“字符”长,总共 6 个“字符”。反转整个字符串时,所有 6 个“字符”必须按顺序(即不反转)保持在一起。 因此“char”数据类型具有误导性。 “字符”是一个松散的术语。 “char”类型实际上只是 UTF16 块大小,我们称它为字符,因为代理对的出现相对较少(即它通常代表一个完整的字符代码点),所以“字符”实际上是指单个 unicode 代码点,但随后使用组合字符,您可以拥有显示为单个“字符/字素/文本元素”的字符序列。这不是航天科技;概念很简单,但语言很混乱。 在开发 Java 时,Unicode 还处于起步阶段。 Java 在 Unicode 出现代理对之前已经存在了大约 5 年,所以当时 16 位 char 非常适合。现在,使用 UTF-8 和 UTF-32 比使用 UTF-16 要好得多。【参考方案5】:

小序言

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 的 8 位块A = 0041 - 使用 UCS-2 的 16 位块Ω = CE A9 - 两个使用 UTF-8 的 8 位块Ω = 03A9 - 一个使用 UCS-2 的 16 位块

问题

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

随着时间的推移,新的亚洲字符集被添加,仅中文符号就占据了 70,000 多点。现在,甚至还有 Emoji points 作为标准的一部分?。添加了新的 16 个“附加”Planes。 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,称为 Low Surrogate,分配给 UTF-16。

通过这些更改,BMP 被 UTF-16 中的 1 个 16 位块覆盖,而所有“补充字符”都被 代理对 覆盖,每个 16 位呈现 2 个块,总共 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。 代理解决方案打开了一些security problems,以及尝试使用“非法代理对”。

许多历史细节被隐藏以跟随主题⚖。 最新的 Unicode 标准可以在http://www.unicode.org/versions/latest找到。

【讨论】:

您的“安全问题”链接已损坏。 谢谢@Indolering,我没有找到旧链接,它是基于UCS2到UTF16的博客系列:archives.miloush.net/michkap/archive/2009/06/10/9723321.html。用链接更新了文本。 非常好的答案,我认为它应该得到更多的选票。一个错字是 BPM,应该是 BMP(基本多语言平面)?【参考方案6】:

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

【讨论】:

“字符”就是这样一个加载项。 Unicode 中没有字符,但有代码点。每个代码点可以呈现为零到多个字符。【参考方案7】:

代理对是 UTF-16 中的两个“代码单元”,它们构成一个“代码点”。 Java 文档声明这些“代码点”仍然有效,它们的“代码单元”顺序正确,反之亦然。它进一步指出,两个未配对的代理代码单元可以反转并形成有效的代理对。也就是说,如果有不成对的代码单元,那么有可能反向的可能不一样!

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

哎呀!

【讨论】:

java设计模式之代理学习与掌握

文章目录什么是代理代理分类两种代理的优缺点及应用场景实践理解两种代理主要区别文章讲静态代理和动态代理两种代理。什么是代理对其他对象提供一种代理,用来控制对这个被代理对象的访问。简单来说,在某些... 查看详情

如何删除Java中的代理字符?

】如何删除Java中的代理字符?【英文标题】:HowtoremovesurrogatecharactersinJava?【发布时间】:2012-10-0317:41:48【问题描述】:我面临的情况是,我在保存到MySql5.1的文本中获得了代理字符。由于此处不支持UTF-16,因此我想在将其保存... 查看详情

java反射之静态and动态代理

首先说一下我们什么情况下使用代理?(1)设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑(sometimesthecodeisreallylikeshit),这时就很难去... 查看详情

nginx前端常用配置

...一些基础知识,nginx是一个高性能的反向代理服务器那么什么是反向代理呢?代理是在服务器和客户端之间假设的一层服务器,代理将接收客户端的请求并将它转发给服务器,然后将服务端的响应转发给客户端。不管是正向代理... 查看详情

spring学习记录

...取动态代理  1.通过动态代理可以体现aop思想  2.为什么要哦用动态代理:对目标对象中的方法进行增强springaop开发  spring封装了动态代理代码,我们不需要手写动态代理代码  还封装了cglib代理——>可以对任何类进... 查看详情

代码点索引的java子串(将代理代码单元对作为单个代码点处理)(代码片段)

...。我想知道我的解决方案是否运作良好或者我是否遗漏了什么。我考虑过发布在codereview上,但这与Java的Strings实现有很大关系,而不是简单的代码本身。publicclassSubstringTestpublicstaticvoidmain(String[]args) 查看详情

对比java学kotlin代理(代码片段)

Java代理当我们需要对某个对外公开的API做一些拦截时,我们可以使用代理。常见的应用场景包括内部校验、将已废弃但是又无法删除的方法委托给新的代理类处理等(有点挂羊头卖狗肉的意思)。比如://内部校... 查看详情

java中的null是什么?

什么是null?null是一个什么样的实例?null属于什么样的集合?它是如何在记忆中表现出来的?答案null是什么的实例?不,没有任何类型的null是instanceof。15.20.2TypeComparisonOperatorinstanceofRelationalExpression:RelationalExpressioninstanceofReference... 查看详情

什么是 Java 中的“常规文件”?

】什么是Java中的“常规文件”?【英文标题】:Whatisa"regularfile"inJava?【发布时间】:2013-12-3102:04:35【问题描述】:类BasicFileAttributes,用于检查文件系统中文件的属性,具有方法isRegularFile()。不幸的是,Javadoc描述相当缺... 查看详情

什么是“字符串参数 []”?主要方法Java中的参数

】什么是“字符串参数[]”?主要方法Java中的参数【英文标题】:Whatis"Stringargs[]"?parameterinmainmethodJava【发布时间】:2020-05-1117:12:08【问题描述】:我刚刚开始用Java编写程序。以下Java代码是什么意思?publicstaticvoidmain(Strin... 查看详情

什么是 Java 中的双大括号初始化?

】什么是Java中的双大括号初始化?【英文标题】:WhatisDoubleBraceinitializationinJava?【发布时间】:2010-12-2920:10:51【问题描述】:什么是Java中的双大括号初始化语法(...)?【问题讨论】:见***.com/questions/1372113/…另见***.com/q/924285/45935... 查看详情

代理模式(proxy)

代理模式(Proxy)代理模式:简单明了。简称代理商,对代理这个词想必大家都不陌生,现在微信上,几乎全是各种代理商,哈哈哈。。。不错。我们的代理模式,也是如此。用java语言来说。就是,替原对象进行一些操作。比如... 查看详情

什么是 value:while 在 Java 中的含义? [复制]

】什么是value:while在Java中的含义?[复制]【英文标题】:Whatisvalue:whilemeaninJava?[duplicate]什么是value:while在Java中的含义?[复制]【发布时间】:2018-08-1912:25:14【问题描述】:我已经阅读了一些在Java中使用这种语法的教程,但我不知... 查看详情

Java中的实例变量是啥?

...英文标题】:WhatisaninstancevariableinJava?Java中的实例变量是什么?【发布时间】:2013-05-1704:38:17【问题描述】:我的任务是制作一个带有实例变量的程序,一个字符串,应该由用户输入。但我什至不知道实例变量是什么。什么是实... 查看详情

java项目中的classpath到底是什么

https://segmentfault.com/a/1190000015802324     查看详情

java中的是什么意思?

java中有2个地方有,一个是特殊字符,另一个是在正则表达式中表示边界的意思。我们这里只讨论特殊字符 我这里一共接受到几种解释:  1、退格符相当于键盘上的Backspace符号    backspace符号是删除的意思,操作有... 查看详情

正向代理与反向代理(代码片段)

https://www.cnblogs.com/Anker/p/6056540.html正向代理与反向代理"""正向代理是对客户端的代理,由客户端设立,客户端了解代理服务器和目标服务器,但是目标服务器不了解真正的客户端是谁;使用正向代理可以达到突破访问限制,提高... 查看详情

java中的publicvoid是什么意思

最基本的语法:publicclassHelloWorld{publicstaticvoidmain(String[]args){System.out.println("HelloWorld");}}java里public是类的访问修饰符,void是表示空类型,没有返回数据。publicvoid用于休息方法,说明该方法在项目中都能被访问,没有返回值。public... 查看详情