6

我正在尝试找到一个子字符串方法或 characterAt 方法,该方法适用于在 JAVA 中包含 UTF-8 编码文本的字符串。

在内部,JAVA 使用 UTF-16。这意味着字符串由大小为 2 个字节的字符组成。一个 UTF-8 字符的大小最多为 6 个字节。当 JAVA 将其存储在字符串中时,它将 UTF-8 字符拆分为多个字符。

例如:字符 U+20000(UTF-8 Hex:F0 A0 80 80)在 JAVA 内部存储为带有两个字符(UTF-16 Hex:D840 和 DC00)的字符串。

当您有一个包含 4 字节 UTF-8 字符的字符串并使用长度时,答案是“2”。当您使用 substring(0,1) 时,您将获得字符的前半部分。

一些代码来说明这一点:

    ByteBuffer inputBuffer = ByteBuffer.wrap(new byte[]{(byte)0xF0, (byte)0xA0, (byte)0x80, (byte)0x80});
    CharBuffer data = Charset.forName("UTF-8").decode(inputBuffer);
    String string_test = data.toString();
    int length = string_test.length();
    String first_half = string_test.substring(0, 1);
    String second_half = string_test.substring(1, 2);
    String full_character = string_test.substring(0, 2);

所有这一切,即使出乎意料,也不是错误,因为 JAVA 在 UTF-16 中工作。固有的 UTF-8 支持会很好。但它不存在。

JAVA 在默认库中是否有任何类,或者是否存在某个提供 UTF-8 支持的类?如:

  • utf8string.length() - 如果其中有一个 4 字节字符,
    则 返回 1
  • utf8string.getCharacterAt(0) - 返回第一个字符,而不是前半部分。
  • utf8string.substring(0,1) - 返回第一个字符,而不是前半部分。

或者,对此常用的解决方案是什么?读取 UTF-8 文件时将所有非 UTF-16 支持的 UTF-8 字符转换为默认的 UTF-16 字符?结果,丢失了 UTF-16 不支持的代码点范围内的所有字符信息?这在我的具体实现中不一定是一个问题,所以如果有一种通用的方法可以做到这一点,我会感兴趣。

4

2 回答 2

8

JAVA 在默认库中是否有任何类,或者是否存在某个提供 UTF-8 支持的类?

你真的不是在追求 UTF-8 支持。您使用的是 Unicode 代码点(纯 32 位整数),而不是 UTF-16 代码单元。是的,Java 对此提供了支持,但使用起来并不容易

例如,要获取特定的代码点,请使用String.codePointAt- 请记住,您提供的索引是根据 UTF-16 代码单元,而不是代码点。

要查找代码点的长度,请使用String.codePointCount.

要查找子字符串,您需要以 UTF-16 代码单元的形式查找偏移量,然后使用普通substring方法;用于String.offsetByCodePoints查找正确的索引。

基本上通过StringAPI 查看所有包含codePoint.

于 2013-07-08T10:36:14.197 回答
0

您应该寻找的是 Java 对 UTF-32 的原生支持。检查String#*codePoint*方法,例如codePointAt.

于 2013-07-08T10:35:34.400 回答