【问题标题】:How to get full list of UTF8 charset in Java [closed]如何在 Java 中获取 UTF8 字符集的完整列表 [关闭]
【发布时间】:2021-02-08 23:55:59
【问题描述】:

我想添加一个测试套件,它将在整个 Unicode 字符集上运行。有没有办法获取 Unicode 字符的完整列表?大多数在线资源都在讨论如何编码和解码,但没有找到有关如何获取完整列表的有用材料。

【问题讨论】:

  • UTF-8 是一种编码,而不是字符集。 UTF-16 和 UTF-32 以及 Unicode 的一些替代编码,这是一个真正的字符集

标签: java unicode


【解决方案1】:

TL;DR:您可能想跳到更下方的“可见代码点”部分。


所有代码点

每个Unicode 字符(code point)都可以编码为UTF-8。正如维基百科所说:

UTF-8 能够使用一到四个一字节(8 位)代码单元对 Unicode 中的所有 1,112,064 个有效字符 code points 进行编码。

Unicode 包含 0hex 到 10FFFFhex 范围内的 1,114,112 个代码点。

所以,要获取所有 UTF-8 字符:

// Build string with every Unicode character
int[] codePoints = new int[0x110000]; // 0 - 0x10FFFF
for (int i = 0; i < codePoints.length; i++)
    codePoints[i] = i;
String allChars = new String(codePoints, 0, codePoints.length);

// Convert to UTF-8
byte[] allUtf8Sequences = allChars.getBytes(StandardCharsets.UTF_8);

// Print statistics
System.out.printf("Code points: %d = 0x%1$x%n", codePoints.length);
System.out.printf("Java chars : %d = 0x%1$x%n", allChars.length());
System.out.printf("  Surrogate pairs: %d = 0x%1$x%n", allChars.length() - codePoints.length);
System.out.printf("UTF-8 bytes: %d = 0x%1$x%n", allUtf8Sequences.length);
System.out.printf("  Average bytes per code point: %.2f%n", (double) allUtf8Sequences.length / codePoints.length);

输出

Code points: 1114112 = 0x110000
Java chars : 2162688 = 0x210000
  Surrogate pairs: 1048576 = 0x100000
UTF-8 bytes: 4384642 = 0x42e782
  Average bytes per code point: 3.94

可见代码点

请注意,目前并非所有代码点都由 Unicode 定义。如果您想限制为已定义的字符,请使用 Character.isDefined(codePoint)

您也可能不想跳过控制字符和空白字符。要跳过所有这些,只检查可见字符,我们可以使用 Character.getType(codePoint) 检查字符类型:

// Build string with visible Unicode characters
int[] codePoints = new int[Character.MAX_CODE_POINT + 1];
int count = 0;
for (int codePoint = 0; codePoint < codePoints.length; codePoint++) {
    switch (Character.getType(codePoint)) {
        case Character.UNASSIGNED:
        case Character.CONTROL:     // Cc
        case Character.FORMAT:      // Cf
        case Character.PRIVATE_USE: // Co
        case Character.SURROGATE:   // Cs
        case Character.SPACE_SEPARATOR:     // Zs
        case Character.LINE_SEPARATOR:      // Zl
        case Character.PARAGRAPH_SEPARATOR: // Zp
            break; // Skip
        default:
            codePoints[count++] = codePoint;
    }
}
String chars = new String(codePoints, 0, count);

// Convert to UTF-8
byte[] utf8bytes = chars.getBytes(StandardCharsets.UTF_8);

// Print statistics
System.out.printf("Code points: %d = 0x%1$x%n", count);
System.out.printf("Java chars : %d = 0x%1$x%n", chars.length());
System.out.printf("  Surrogate pairs: %d = 0x%1$x%n", chars.length() - count);
System.out.printf("UTF-8 bytes: %d = 0x%1$x%n", utf8bytes.length);
System.out.printf("  Average bytes per code point: %.2f%n", (double) utf8bytes.length / count);

输出

Code points: 143679 = 0x2313f
Java chars : 231980 = 0x38a2c
  Surrogate pairs: 88301 = 0x158ed
UTF-8 bytes: 517331 = 0x7e4d3
  Average bytes per code point: 3.60

【讨论】:

  • 请注意,某些代码点本身无效 - 即代理对...
  • @JohannesKuhn 是的,我也意识到了这一点,并且在您发表评论时正在添加答案。
  • 现在这是一个很好的答案。
  • 感谢您提供详细信息和代码示例。它确实对我有很大帮助,但有些地方我并不完全理解。 1. Unicode 包含 1,114,112 个码点,Character.MAX_CODE_POINT 明显比它小,这意味着 java 不支持完整的 unicode 字符? 2. java buildin Character.isDefined 方法声明“确定字符(Unicode 代码点)是否以 Unicode 定义。”但显然它过滤掉了一些代码点,这似乎与方法描述/语句相矛盾?
  • 其实我收回第一个问题。我误读了您示例的输出。
猜你喜欢
  • 2018-09-04
  • 1970-01-01
  • 2011-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-09
  • 1970-01-01
  • 2019-02-12
相关资源
最近更新 更多