如何从 unicode 字符范围打印 utf-8 字符?

How to print utf-8 characters from unicode character ranges?

单个字符转换为

final String str2 = "\u0026";
System.out.println(str2); // which ­prints & character

现在我想在给定范围内打印它,例如[\u0621-\u0652] 但我不确定如何在循环中增加 uniocde 字符以打印 utf-8 中的单个字符。

I can convert the single unicode character to utf-8 like this

不,你不能。

"\u0026".getBytes()

在 java 中,字符串 unicode。这是将 unicode 代码点 0026 放入字符串中。然后,getBytes() 通过 平台默认编码方案 将字符串转换为字节数组,即¯\(ツ)/ ¯ 谁知道它是什么。在 windows 上可能是 Cp1252。在日本计算机上,它可能是一些汉字变体。如果平台默认编码无法对该字符进行编码,它甚至可能会抛出异常。在大多数 linux 变体上,平台默认 IS UTF-8,但没有任何保证。

new String(thoseBytes, StandardCharsets.UTF_8)

如果平台默认编码是 UTF_8,您将一事无成:您获取了一个字符串,通过 UTF-8 将其转换为字节,然后使用 UTF 将这些字节转换为字符串-8,从而保证您最终得到的是原件。这是一种愚蠢、低效的写法:`final String str2 = "\u0026";.

如果平台默认设置是 而不是 UTF-8,那么您只是做了一个毫无意义的官方转换。 str2 包含垃圾。鉴于 \u0026 在许多编码中表示相同的符号,尤其是倾向于平台默认值的编码,很可能你得到 'lucky' 而 str2 仍然是字符串 "\u0026"。但是没有任何保证。

因此,您所做的是不进行任何转换 - 或者,您已将字符串转换为垃圾(与获取图像、将其保存为 PNG、然后使用 JPG 解码器读取该 PNG 的方式相同)使解码器崩溃并产生无意义的垃圾)。这两个听起来都没什么用。

试一试:

System.out.println("\u0026");

只是 运行 那个。它将打印符号字符 always,而您的代码只是在大多数平台上这样做,但不是全部。

Now I want to print it for a given range for e.g. [\u0621-\u0652]

听起来很简单。

char start = '\u0621';
char end = '\u0652';
for (int c = start; c <= end; c++) {
    System.out.println(c);
}

您似乎对 UTF-8 和 unicode 是什么感到困惑。

unicode 是一个巨人 table。它将数字,例如 38(\u0026 是十六进制表示法:38 的十六进制)映射到一个概念,通常是一个字符,例如 'an ampersand'.

没有再描述任何东西。特别是它并没有说字节 38 表示&符号。它根本没有提到字节; unicode 不知道字节是什么。

程序员的明显跟进是:好的,太好了,所以如果我有,说,“你好,再见!”作为一个字符串,unicode 准确地告诉我哪个数字序列正确地描述了其中的每个字符。但是我该如何处理我的 'bunch o numbers'?我应该如何在文件中对这些进行编码(这是一个 bag-of-bytes。鉴于 unicode 定义了一个巨大的范围,并且字节最多只能描述 256 个数字,你不能只是去:“好吧,将每个数字存储为一个字节").

THAT 是 UTF-8 出现的地方。UTF-8 与 unicode 不同。它是一种存储数字的编码。具体来说,旨在通过将字符串映射到它们的 unicode 数字来有效地存储将字符串转换为一系列数字时可能获得的数字类型。

因此,'\u0621' 不是 UTF。直接是 unicode 中的字符。编码为 UTF-8 的字符实际上是 two-byte 序列 0xD8 0xA1。看起来一点也不像 0621。

试一试:

byte[] b = new byte[] { (byte) 0xD8, (byte) 0xA1 };
String s = new String(b, StandardCharsets.UTF_8);
System.out.println("The string: " + s);
System.out.println("The codepoint for that first char: " + (int) s.charAt(0));

将打印:

The String: ء
The codepoint for that first char: 1569

1569 是 0x0621 的十进制版本。

注意:正如 Mike 在评论中指出的那样,如果您真的想使用 unicode 字符,它们被称为 'codepoints',而 char 不能完全存储它们。您会使用 .getCodepointAt() 和字符串 class 中的朋友,但这相当高级,使示例复杂化,并且对于回答问题并不重要。

您可以使用 takes unicode codepoints as input:

的 String 构造函数轻松完成此操作
import java.util.Arrays;

public class Main {
  public static void main(String []args){

    // unicode codepoints are hexadecimal, so we specify them using hex notation:
    int start = 0x0621;
    int end = 0x0652;

    // The unicode building version of new String needs an array of ints,
    // even if we're only trying to build a single-letter String.
    int[] data = {0};

    for(int i=start; i<=end; i++) {
      data[0] = i;
      System.out.print( new String(data, 0, 1) );
    }
  }
}

生成输出:

ءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّْ.

(它试图执行阿拉伯文本整形,因为我们使用的是 print,而不是 println,但这与将 unicode 代码点数字转换为实际字符串的练习并没有真正的关系)

然后将 java-internal 字符串数据转换为明确的 UTF8 编码字节序列是一件微不足道的事情 one-liner,在 How to convert Strings to and from UTF8 byte arrays in Java

上进行了解释