8

随着jdk12,出现了国际象棋符号(来源):

Unicode 11.0.0 引入了以下现在包含在 JDK 12 中的新功能

[...] 以下现有脚本的 4 个块:

  • 格鲁吉亚语扩展

  • 玛雅数字

  • ndic Siyaq 号码

  • 国际象棋符号

考虑到这一点,我尝试使用以下代码打印这些字符,以测试功能并在稍后的小象棋游戏中使用它们:

Character.UnicodeBlock block = Character.UnicodeBlock.CHESS_SYMBOLS;
for (int i = 0; i < 1114112; i++) {
    char unicode = (char) i;
    if(Character.UnicodeBlock.of(unicode) == block) {
        System.out.println(unicode);
    }
}

但是,它没有打印任何东西。CHESS_SYMBOLS例如,如果我替换为ARABIC. 我有 java 12.0.1。

问题:为什么上面的代码没有打印任何东西?

4

2 回答 2

8

Miscellaneous Symbols 块中存在一些国际象棋符号字符,但您专门检查不同块中的 16 位char值。Chess Symbols 块包含16 位值的零个字符;它从 U+1FA00 开始,到 U+1FA6F 结束。

通过强制转换为char,您将所有高于 U+FFFF 的值修剪为它们的最低 16 位;例如,如果i0x1fa60,将其转换为 achar将使其成为 0xfa60,这会阻止您的块检查成功。

为了使您的代码工作,您需要停止假设所有代码点都是 16 位值。你可以通过改变这个来做到这一点:

char unicode = (char) i;

对此:

int unicode = i;
于 2019-05-14T13:29:46.693 回答
4

不幸的是Character.UnicodeBlock,没有方法来判断块内代码点的开始值和结束值是什么。在 Unicode 11 中,国际象棋符号块从 U+1FA00 运行到 U+1FA6D。

Java 使用 UTF-16 和代理对来表示超过 U+10000 的字符。在这种情况下,代码点 U+1FA00 将表示为两个char值:U+D83E(高代理)和 U+DE60(低代理)。

您应该使用Character.toChars()正确打印始终为的代码点int

Character.UnicodeBlock block = Character.UnicodeBlock.CHESS_SYMBOLS;
for (int i = 0; i < 1114112; i++) {
    if (Character.UnicodeBlock.of(i).equals(block)) {
        System.out.println(Character.toChars(i));
    }
}
于 2019-05-14T13:30:14.440 回答