【问题标题】:how to construct string using surrogate pairs如何使用代理对构造字符串
【发布时间】:2021-06-22 22:07:58
【问题描述】:

根据https://docs.oracle.com/javase/8/docs/api/java/lang/Character.html,我正在尝试通过使用高代理范围 (\uD800-\uDBFF) 或低代理范围内的代码点来构造一个字符。 代码示例是

      for (int cp = Character.MIN_SURROGATE; cp <= Character.MAX_SURROGATE; cp++) {
            char c = (char) cp;
            if (Character.isHighSurrogate(c)) {
                char low = Character.lowSurrogate(cp);
                System.out.println(Character.isSurrogatePair(c, low));
            } else if (Character.isLowSurrogate(c)) {
                char high = Character.highSurrogate(cp);
                System.out.println(Character.isSurrogatePair(high, c));
            }
        }

让我困惑的是,所有高代理字符都可以通过调用Character.lowSurrogateCharacter.isSurrogatePair(c, low)找到对应的低代理对总是正确的,但低代理char找不到对应的高代理对和Character.highSurrogat总是返回与代码点 55287 相同的字符。

知道如何在给定低代理字符的情况下构造一个有效字符吗?

【问题讨论】:

    标签: java unicode


    【解决方案1】:

    您对什么是代理以及它们如何协同工作存在根本性的误解。我建议你阅读how UTF-16 actually works

    Character.is(High|Low)Surrogate()UTF-16 代码单元 作为输入。如果结果是true,则在相同的数值 上调用Character.(high|low)Surrogate() 不会像您认为的那样做。您无法找到从高代理中找到低代理,反之亦然。任何高代理都可以与许多不同的低代理组合(即D800 DC00D800 DC01D800 DC02、...),反之亦然,任何低代理都可以与许多不同的高代理组合(即@987654331 @, D801 DC00, D802 DC00, ...),生成不同的 Unicode 代码点。

    Character.(high|low)Surrogate()Unicode 代码点 作为输入,并分别返回以 UTF-16 编码该代码点所需的高/低代理。

    您正在枚举 codeunits 并将它们 视为 它们是 codepoints,它们不是(codepointsUTF-16 代理项 范围内是保留的,因此在任何上下文中都无效)。 IOW,你是在混合苹果和橘子,所以结果当然不是你所期望的。

    让我们在上下文中更深入地了解您的代码示例。让我们看看循环处理的两个极端,Character.MIN_SURROGATE ('\uD800') 和 Character.MAX_SURROGATE ('\uDFFF')。两者之间的所有其他值也是如此:

    • isHighSurrogate((char)0xD800) 返回 trueCharacter.isLowSurrogate((char)0xD800) 返回 false,因为 codeunit D800high 代理代码单位的范围内 (D800..DBFF )。

    • isHighSurrogate((char)0xDFFF) 返回 falseCharacter.isLowSurrogate((char)0xDFFF) 返回 true,因为 codeunit DFFFlow 代理代码单位的范围内 (DC00..DFFF )。

    • Character.lowSurrogate((int)0xD800)Character.highSurrogate((int)0xDFFF) 都返回 unspecified char 值,因为 0xD8000xDFFF 在 @ 范围内不是有效的“补充字符”(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_POINTMAX_CODE_POINT 之间,则为 true;否则为假。

    所以,一般来说,如果Character.isHighSurrogate() 返回true,则相同数值Character.lowSurrogate()未定义。如果Character.isLowSurrogate() 返回true,则Character.highSurrogate() 对于相同的数值未定义

    因此,您声称“所有高代理项字符都可以通过调用 Character.lowSurrogate 找到相应的低代理项对”和“Character.isSurrogatePair(c, low) 始终为真”都错了。

    您声称“低代理字符无法找到相应的高代理对”是正确的,但您声称“Character.highSurrogate 始终返回与代码点相同的字符55287”是错误的。

    最后,关于您的实际问题:

    知道如何在给定低代理字符的情况下构造一个有效字符吗?

    您不能仅从高或低代理项构建 Unicode 代码点。正是高+低代理共同作用组合定义了一个特定的代码点。你需要两个代理人。如果您只有 1 个代理,那么您没有足够的位来重新构建代码点。期间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-13
      • 1970-01-01
      • 2011-02-13
      • 2013-06-26
      相关资源
      最近更新 更多