【问题标题】:Unicode code points array is converted to String and back with changesUnicode 代码点数组转换为字符串并返回更改
【发布时间】:2021-01-12 23:44:56
【问题描述】:

定义了 Unicode 码位的数组是:

int[] unicodeDefinedCodePoints = IntStream
            .rangeClosed(Character.MIN_CODE_POINT, Character.MAX_CODE_POINT)
            .filter(Character::isDefined)
            .toArray();

让我们将其转换为字符串并返回代码点:

int[] unicodeDefinedCodePointsAfterTransformation =
            new String(unicodeDefinedCodePoints, 0, unicodeDefinedCodePoints.length)
                .codePoints()
                .toArray();

我希望得到相同的数组,但是

  1. 转换后的数组不包含代码点 56319 和 56320
  2. 转换后代码点 1113088 重复

以上代码点的代码都是十进制的。

使用的Java版本是:

openjdk version "1.8.0_275"
OpenJDK Runtime Environment (IcedTea 3.17.1) (build 1.8.0_275-b01 suse-1.1-x86_64)
OpenJDK 64-Bit Server VM (build 25.275-b01, mixed mode)

有什么想法吗?

谢谢。

【问题讨论】:

  • 专业提示:在谈论 Unicode 代码点时,给出十六进制表示法几乎总是更有用。 56319 是 U+DBFF,56320 是 U+DC00,1113088 是 U+10FC00。仅此一项就可以通过查找这些代码点的定义来帮助您入门。不:我不知道到底发生了什么,但所有这些都接近“圆形边界”这一事实让我认为这种疯狂背后有一些原因。
  • 前两个是代理,最后一个是私用。
  • @Thed,你到底想在这件事上完成什么?
  • 我需要测试一个词法分析器。应该有两个测试,第一个带有词法分析器预期的输入,因此产生一些标记,第二个带有词法分析器意外的输入。我需要检查词法分析器是否不会产生任何带有意外输入的标记。为了进行意外输入,我将所有已定义的 Unicode 代码点收集到一个数组中,删除预期的代码点,然后创建一个剩余代码点的字符串。事实证明,将提到的代码点数组转换为字符串至少可能有这样奇怪的副作用。将调试它。

标签: java unicode


【解决方案1】:

没有明确的答案

  • 56319 是 U+DBFF,私用高代理,最后一个。
  • 56320 是 U+DC00,低代理,第一。
  • 1113088 isU+10FC00,无效字符。

可能是先处理高代理,然后处理低代理。无效字符当然是单例黑洞;失败时的替换字符。

对于代理对,只需递减,或用一个代码点制作两个字符串。

int[] unicodeDefinedCodePoints = IntStream
        .rangeClosed(-Character.MAX_CODE_POINT, -Character.MIN_CODE_POINT)
        .map(Math::abs)
        .filter(Character::isValidCodePoint)
        .toArray();

我认为isDefined和isValidCodePoint之间没有区别,但后者更清楚。

【讨论】:

  • 感谢re surrogate pair processing的idea,我刚刚记得我在JDK中看到了类似的方法。看起来我需要更深入地阅读标准。与 1113088 (U+10FC00) 一样,Character.isValidCodePoint() 为它返回 true。至于isDefinedisValidCodePoint 之间的区别,在我的例子中,第一个返回249704 个代码点,最后一个给出1114112 个代码点。也就是说,MIN-to-MAX 范围内的所有代码点都被认为是有效的,但我只需要那些有意义的代码点。
【解决方案2】:

有效的 Unicode 代码点是介于 0 (MIN_CODE_POINT) 和 1114111 (MAX_CODE_POINT) 之间的代码点。但是,55296 (MIN_SURROGATE) 和 57343 (MAX_SURROGATE) 之间的代码点保留给 highSurrogate 和 lowSurrogate,它们形成对来表示代码点介于 65536 和 1114111 之间的字符,因为 65535 是可以存储为 2 字节的最大数字字符。 要获取所有有效 unicode 代码点的数组,您必须排除代理项,如下所示。

int[] unicodeDefinedCodePoints = IntStream
     .rangeClosed(Character.MIN_CODE_POINT, Character.MAX_CODE_POINT)
     .filter((i) -> i < Character.MIN_SURROGATE || i > Character.MAX_SURROGATE)
     .toArray();

数组应包含所有 1112064 个有效代码点。

【讨论】:

  • 感谢 Paweł!终于有时间阅读标准了。代理虽然是分配代码点,但不能分配给抽象字符。因此,a) 它们对于处理编码 文本数据独立于其编码形式 的应用程序无关紧要,并且b) 在以某种方式转换为字符串时可能会导致奇怪的错误。像往常一样,有些东西在标准和代码中的命名不同。标准中的“已分配”代码点在代码中被命名为“已定义”。好的。有isSurrogate(char ch)isSurrogate(int i) 在哪里?像往常一样,我想知道。
猜你喜欢
  • 2019-06-13
  • 2018-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 2020-01-21
  • 1970-01-01
相关资源
最近更新 更多