您对什么是代理以及它们如何协同工作存在根本性的误解。我建议你阅读how UTF-16 actually works。
Character.is(High|Low)Surrogate() 将 UTF-16 代码单元 作为输入。如果结果是true,则在相同的数值 上调用Character.(high|low)Surrogate() 不会像您认为的那样做。您无法找到从高代理中找到低代理,反之亦然。任何高代理都可以与许多不同的低代理组合(即D800 DC00、D800 DC01、D800 DC02、...),反之亦然,任何低代理都可以与许多不同的高代理组合(即@987654331 @, D801 DC00, D802 DC00, ...),生成不同的 Unicode 代码点。
Character.(high|low)Surrogate() 将 Unicode 代码点 作为输入,并分别返回以 UTF-16 编码该代码点所需的高/低代理。
您正在枚举 codeunits 并将它们 视为 它们是 codepoints,它们不是(codepoints 在 UTF-16 代理项 范围内是保留的,因此在任何上下文中都无效)。 IOW,你是在混合苹果和橘子,所以结果当然不是你所期望的。
让我们在上下文中更深入地了解您的代码示例。让我们看看循环处理的两个极端,Character.MIN_SURROGATE ('\uD800') 和 Character.MAX_SURROGATE ('\uDFFF')。两者之间的所有其他值也是如此:
-
isHighSurrogate((char)0xD800) 返回 true 和 Character.isLowSurrogate((char)0xD800) 返回 false,因为 codeunit D800 在 high 代理代码单位的范围内 (D800..DBFF )。
-
isHighSurrogate((char)0xDFFF) 返回 false 和 Character.isLowSurrogate((char)0xDFFF) 返回 true,因为 codeunit DFFF 在 low 代理代码单位的范围内 (DC00..DFFF )。
-
Character.lowSurrogate((int)0xD800) 和 Character.highSurrogate((int)0xDFFF) 都返回 unspecified char 值,因为 0xD800 和 0xDFFF 在 @ 范围内不是有效的“补充字符”(Unicode 代码点) 987654356@(U+10000..U+10FFFF),即Character.isSupplementaryCodePoint()返回false。根据 Java 的文档:
lowSurrogate()
返回以 UTF-16 编码表示指定补充字符(Unicode 代码点)的代理对的尾随代理(低代理代码单元)。 如果指定字符不是补充字符,则返回未指定的char。
highSurrogate()
返回以 UTF-16 编码表示指定补充字符(Unicode 代码点)的代理项对的前导代理项(高代理项代码单元)。 如果指定字符不是补充字符,则返回未指定的char。
isSupplementaryCodePoint()
判断指定字符(Unicode码位)是否在补充字符范围内。
...
返回:
如果指定的代码点介于 MIN_SUPPLEMENTARY_CODE_POINT 和 MAX_CODE_POINT 之间,则为 true;否则为假。
所以,一般来说,如果Character.isHighSurrogate() 返回true,则相同数值的Character.lowSurrogate() 是未定义。如果Character.isLowSurrogate() 返回true,则Character.highSurrogate() 对于相同的数值 是未定义。
因此,您声称“所有高代理项字符都可以通过调用 Character.lowSurrogate 找到相应的低代理项对”和“Character.isSurrogatePair(c, low) 始终为真”都错了。
您声称“低代理字符无法找到相应的高代理对”是正确的,但您声称“Character.highSurrogate 始终返回与代码点相同的字符55287”是错误的。
最后,关于您的实际问题:
知道如何在给定低代理字符的情况下构造一个有效字符吗?
您不能仅从高或低代理项构建 Unicode 代码点。正是高+低代理共同作用的组合定义了一个特定的代码点。你需要两个代理人。如果您只有 1 个代理,那么您没有足够的位来重新构建代码点。期间。