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

use*_*426 2 java unicode utf-8

单字符转换为

\n
final String str2 = "\\u0026";\nSystem.out.println(str2); // which \xc2\xadprints & character\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

rzw*_*oot 7

\n

我可以像这样将单个 unicode 字符转换为 utf-8

\n
\n

不,你不能。

\n
\n

"\\u0026".getBytes()

\n
\n

在java中,字符串unicode的。这会将 unicode 代码点放入0026字符串中。然后,getBytes()通过平台默认编码方案\xc2\xaf\\ (\xe3\x83\x84) /\xc2\xaf 将该字符串转换为字节数组,谁知道它是什么。在 Windows 上可能是 Cp1252。在日本计算机上,它可能是某种汉字变体。如果平台默认编码无法对该字符进行编码,它甚至可能会引发异常。在大多数 Linux 变体上,平台默认值UTF-8,但没有任何保证。

\n
\n

new String(thoseBytes, StandardCharsets.UTF_8)

\n
\n

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

\n

如果平台默认值不是UTF -8,那么您只是做了一个毫无意义的官方转换。str2含有垃圾。鉴于 \\u0026 在许多编码中表示相同的符号,尤其是往往是平台默认值的编码,很可能您会“幸运”并str2保留 string "\\u0026"。但没有任何保证。

\n

所以,你所做的就是什么都不转换 - 或者,你已经将一个字符串转换为垃圾(与获取图像,将其另存为 PNG,然后使用 JPG 解码器读取该 PNG 的方式相同),要么使解码器崩溃,要么将产生无意义的垃圾)。任何一个听起来都毫无用处。

\n

尝试一下:

\n
System.out.println("\\u0026");\n
Run Code Online (Sandbox Code Playgroud)\n

运行一下就可以了。它会打印&符号,always,而您的代码仅在大多数平台上这样做,但不是全部。

\n
\n

现在我想打印给定范围,例如 [\\u0621-\\u0652]

\n
\n

这就像听起来一样简单。

\n
char start = '\\u0621';\nchar end = '\\u0652';\nfor (int c = start; c <= end; c++) {\n    System.out.println(c);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

unicode 是一个巨大的表。它将数字(例如 38)(\\u0026 采用十六进制表示法:That’s hex for 38)映射到一个概念(通常是一个字符,例如“&”)。

\n

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

\n

对于程序员来说,明显的后续行动是:好的,太好了,所以如果我有,说,“你好,再见!” 作为一个字符串,unicode 准确地告诉我哪个数字序列正确地描述了其中的每个字符。但是我该如何处理我的“一堆数字”呢?我该如何将这些编码到一个文件中(这是一袋字节。鉴于 unicode 定义了一个很大的范围,并且字节只能描述最多 256 个数字,你不能只是说:“好吧,将每个数字存储为一个字节”)。

\n

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

\n

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

\n

尝试一下:

\n
byte[] b = new byte[] { (byte) 0xD8, (byte) 0xA1 };\nString s = new String(b, StandardCharsets.UTF_8);\nSystem.out.println("The string: " + s);\nSystem.out.println("The codepoint for that first char: " + (int) s.charAt(0));\n
Run Code Online (Sandbox Code Playgroud)\n

这将打印:

\n
The String: \xd8\xa1\nThe codepoint for that first char: 1569\n
Run Code Online (Sandbox Code Playgroud)\n

1569 是 0x0621 的十进制版本。

\n

注意:正如 Mike 在评论中指出的那样,如果你真的想使用 unicode 字符,它们被称为“代码点”,并且char不能完全存储它们。您可以使用.getCodepointAt()字符串类中的 and 朋友,但这非常高级,使示例变得复杂,并且对于回答问题并不重要。

\n

  • 我不同意使用该构造函数会使事情变得更容易。我在最后添加了一个注释,在极不可能的情况下,OP 在他们编程生涯的这个阶段担心它是合适的。 (2认同)