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

Java 如何从unicode字符范围打印utf-8字符?,java,unicode,utf-8,Java,Unicode,Utf 8,单字符转换是非常重要的 final String str2 = "\u0026"; System.out.println(str2); // which ­prints & character 现在我想在给定范围内打印它,例如[\u0621-\u0652],但我不确定如何在循环中增加uniocde字符以打印utf-8中的单个字符 我可以像这样将单个unicode字符转换为utf-8 不,你不能 \u0026.getBytes 在java中,字符串是unicode。这

单字符转换是非常重要的

final String str2 = "\u0026";
System.out.println(str2); // which ­prints & character
现在我想在给定范围内打印它,例如[\u0621-\u0652],但我不确定如何在循环中增加uniocde字符以打印utf-8中的单个字符

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

不,你不能

\u0026.getBytes

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

新StringthoseBytes,StandardCharsets.UTF_8

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

如果平台默认值不是UTF-8,那么您刚刚完成了一个毫无意义的gobbledygook转换。str2包含垃圾。鉴于\u0026在许多编码中表示相同的符号,特别是倾向于平台默认值的编码,您很可能会得到“lucky”,并且str2仍然是字符串\u0026。但没有任何保证

所以,你所做的是什么都不转换——或者,你把一个字符串转换成垃圾,就像拍摄一幅图像,将其保存为PNG,然后使用JPG解码器读取PNG一样,要么使解码器崩溃,要么产生无意义的垃圾。任何一个听起来都毫无用处

试试看:

System.out.println("\u0026");
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));
就这么办吧。它将始终打印符号和字符,而您的代码仅在大多数平台上打印,而不是在所有平台上

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

听起来很简单

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

The String: ء
The codepoint for that first char: 1569
1569是0x0621的十进制版本

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

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

不,你不能

\u0026.getBytes

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

新StringthoseBytes,StandardCharsets.UTF_8

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

如果平台默认值不是UTF-8,那么您刚刚完成了一个毫无意义的gobbledygook转换。str2包含垃圾。鉴于\u0026在许多编码中表示相同的符号,特别是倾向于平台默认值的编码,您很可能会得到“lucky”,并且str2仍然是字符串\u0026。但没有任何保证

所以,你所做的是什么都不转换——或者,你把一个字符串转换成垃圾,就像拍摄一幅图像,将其保存为PNG,然后使用JPG解码器读取PNG一样,要么使解码器崩溃,要么产生无意义的垃圾。任何一个听起来都毫无用处

试试看:

System.out.println("\u0026");
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));
就这么办吧。它将始终打印符号和字符,而您的代码仅在大多数平台上打印,而不是在所有平台上

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

听起来很简单

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

The String: ء
The codepoint for that first char: 1569
1569是0x0621的十进制版本


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

您可以使用字符串构造函数轻松地完成此操作,它:

它尝试执行阿拉伯语文本整形,因为我们使用的是打印,而不是pri ntln,但这与将unicode码点号转换为实际字符串的练习并没有太大关系


然后,将java内部字符串数据转换为显式UTF8编码的字节序列是一个简单的单行程序,如

所述,您可以使用字符串构造函数非常轻松地实现这一点:

它尝试执行阿拉伯语文本整形,因为我们使用的是print,而不是println,但这与将unicode码点号转换为实际字符串的练习无关


然后,将java内部字符串数据转换为显式UTF8编码的字节序列是一个简单的单行程序,在

上解释了字符串是UTF-8字符。调用getBytes时,几乎可以肯定会损坏字符数据,因为getBytes使用系统的默认字符集,在Windows上是一个单字节字符集,如Windows-125x。不要将字符串转换为字节,然后再转换回字符串。仅字符串str2=\u0621;已经足够了。第一行是没有意义的,因为您从一个字符串获取的字节数组构造了一个字符串。您可以跳过这两个转换步骤,得到相同的结果。其次,假设平台默认编码为UTF-8,这在Android和某些Linux系统上是正确的,但远不是通用的。更新了描述。只需使用from unicode codepoint构造函数创建字符串对象即可。请参见答案。@VGR字符串是UTF-8字符-Java字符串实际上是UTF-16代码单元的序列,不是UTF-8。您可以从UTF-8字节序列构造字符串,并将字符串转换为UTF-8字节序列,但字符串永远不会包含UTF-8。字符串是UTF-8字符。调用getBytes时,几乎可以肯定会损坏字符数据,因为getBytes使用系统的默认字符集,在Windows上是一个单字节字符集,如Windows-125x。不要将字符串转换为字节,然后再转换回字符串。仅字符串str2=\u0621;已经足够了。第一行是没有意义的,因为您从一个字符串获取的字节数组构造了一个字符串。您可以跳过这两个转换步骤,得到相同的结果。其次,假设平台默认编码为UTF-8,这在Android和某些Linux系统上是正确的,但远不是通用的。更新了描述。只需使用from unicode codepoint构造函数创建字符串对象即可。请参见答案。@VGR字符串是UTF-8字符-Java字符串实际上是UTF-16代码单元的序列,不是UTF-8。你可以从UTF-8字节序列构造一个字符串,并将字符串转换为UTF-8字节序列,但字符串永远不会包含UTF-8。Unicode代码点不适合字符,因为Unicode 3,请不要建议人们为此使用字符,它只会给他们看起来有效的代码,然后在他们走后中断嘿,现在是2020年,让我为Emojit做这个答案已经很长了,但是另一个进入更高平面字符的侧线正在把答案变成一个系列讲座,不是吗?它很长,没有任何好的理由:使用int而不是char来做这个的字符串,所以这堵文本墙应该是真的,你可以通过使用正确的字符串构造函数而不是文本墙来做到这一点。我不同意使用这个构造函数会让事情变得更简单。我在最后添加了一个注释,在极不可能的情况下,OP在其编程生涯的这个阶段担心它是合适的。@Mike'Pomax'Kamermans:检查这个问题最初是如何表达的。这堵文本墙似乎非常有必要修正问题措辞所隐含的误解。我同意这个答案在发布到当前版本的问题旁边时看起来很奇怪。自从Unicode 3以来,Unicode代码点就不适合字符,请不要建议人们使用字符,它只是给了他们似乎有效的代码,然后当他们走的时候就会中断嘿,现在是2020年,让我为Emojit做这个回答。答案已经很长了,另一个进入更高平面字符的侧记是将答案转换成一个系列讲座,不是吗?它相当长,没有任何好的理由:使用int而不是char的字符串,所以这堵文本墙应该是真的,你可以通过使用正确的字符串构造函数而不是文本墙来做到这一点。我不同意使用这个构造函数会让事情变得更简单。我在最后添加了一个注释,在极不可能的情况下,OP在其编程生涯的这个阶段担心它是合适的。@Mike'Pomax'Kamermans:检查这个问题最初是如何表达的。这堵文本墙似乎非常有必要修正问题措辞所隐含的误解。我同意这个答案贴在question.System.out.printf%c的当前版本旁边时看起来很奇怪,I是另一种方法,它可能更容易理解,也可能不容易理解。虽然这是真的,但它忽略了重要的部分不是打印本身,而是一个字符串,您可以进一步操作
使用.System.out.printf%c,i是另一种方法,它可能更容易理解,也可能不容易理解。尽管如此,它忽略了重要的部分不是打印本身,而是一个字符串,您可以进一步使用它。