【问题标题】:Converting string with getBytes between two encodings在两种编码之间使用 getBytes 转换字符串
【发布时间】:2017-02-28 17:35:03
【问题描述】:

我有以下代码:

String s0="Përshëndetje botë!";
byte[] b1=s0.getBytes("UTF8");
byte[] b2=s0.getBytes("ISO8859_1");
String s0_utf8=new String(b1, "UTF8");  //right encoding, wrong characters
//String s0_utf8=new String(b1, "ISO8859_1"); //wrong encoding, wrong characters
String s0_iso=new String(b2, "UTF8");  //wrong encoding; outputs right characters
//String s0_iso=new String(b2, "ISO-8859-1");  //right encoding; if uncommented, outputs damaged characters
System.out.println("s0_utf8: "+s0_utf8);  //
System.out.println("s0_iso: "+s0_iso);

因此,字符串"Përshëndetje botë!" 使用UTF8ISO-8859-1 转换为字节,然后使用相应的编码将这些字节转换回Unicode 字符。此处仅在一种情况下显示正确的字符:如果我们使用ISO8859_1 将原始字符串编码为字节并使用UTF-8 对其进行解码。所有其他情况都会导致错误的字符。

String s0="P\u00ebrsh\u00ebndetje bot\u00eb!";
byte[] b1=s0.getBytes("UTF8");
byte[] b2=s0.getBytes("ISO8859_1");
String s0_utf8=new String(b1, "UTF8"); //right encoding; outputs right characters
//String s0_utf8=new String(b1, "ISO8859_1"); //wrong encoding, wrong characters
String s0_iso=new String(b2, "UTF8");  //wrong encoding; outputs wrong characters
//String s0_iso=new String(b2, "ISO-8859-1");  //right encoding; if uncommented, outputs damaged characters
System.out.println("s0_utf8: "+s0_utf8);  //
System.out.println("s0_iso: "+s0_iso);

这里有两种情况会显示正确的单词:当字符串同时使用相同的编码进行编码和解码时。

我不明白这里发生了什么。这怎么可能? Unicode 的字符表示有何不同?为什么将 enode 与 iso - decode with utf8 工作?结果字符串不应该与原始字符串完全不同吗,因为 utf8 可能对 iso 的字节进行不同的解释?

【问题讨论】:

标签: java unicode encoding utf-8 character-encoding


【解决方案1】:

我的猜测是字符串从一开始就是错误的,因为您的 Java 源文件以编码 A 编码,而编译器使用编码 B 读取它。这就解释了为什么当您使用转义序列而不是出现问题时比口音。

关于

//String s0_iso=new String(b2, "ISO-5589-1");  //right encoding; if uncommented, outputs damaged characters

不,这不是正确的编码。 5589 != 8859.

【讨论】:

  • 这里是一个错字;编辑了帖子。您能否解释一下当编译器起作用时会发生什么?我认为.getBytes() 方法有助于使编译器的编码变得无关紧要——无论在编译过程中使用什么编码,我得到的字节都与我传递给该方法的字节相对应。该文件为 UTF-8,正确的编码应为 ISO-8859-1。但我想尝试仅通过代码来解决这个问题,而不是更改文件/编译器的编码。
  • 您的代码说:获取此字符串,并将其转换为字节。这发生在运行时。因此,字节码需要包含代码中包含的文字字符串的字符。但是要将这些字符放入字节码中,编译器需要从 Java 源文件中读取它们。如果文件以 UTF8 编码,但您告诉编译器它是 UTF8,编译器将无法正确解码 Java 源文件的字节,因此会将不正确的字符放入字节码中(就像您读取 UTF8 文件时使用ISO88591)。
  • 所以起初我们的 UTF8 字节码带有错误的 ISO 字符字节。然后在运行时 JVM 将这些字节码映射回 Unicode 字符并将其再次编码回 UTF8 和 ISO?如果编码都有问题,怎么会显示损坏的符号?
  • 在我的情况下你是对的——我认为 javac 会将源代码(以及源代码中的字符串常量)解释为 UTF-8,但事实并非如此。要修复将“-encoding utf8”开关添加到 javac:javac -encoding utf8 ...etc...
【解决方案2】:

This 的回答确实帮助我理解了发生了什么。

第一种情况

String s0="Përshëndetje botë!";

s0ISO8859_1

b1获取 UTF-8 格式的字节

b2获取 ISO8859_1 中的字节

IDEA 错误地转换了ë 字符 => Përshëndetje botë!

String s0_iso=new String(b2, "UTF8"); 将字符串转换为 IDEA 的编码并正确打印

String s0_iso=new String(b2, "ISO-8859-1"); 不改变原来的字符串 => Përshëndetje botë!

当字符串转换成外部编码(UTF-8)时,麻烦来了:

String d=new String(b1, "UTF8"); => Përshëndetje botë!

String b=new String(b1, "ISO8859_1");=> Përshëndetje botë!

我仍然不完全确定这两种情况发生了什么,但是

d.equals("Përshëndetje botë!")true

我的猜测是当字符串以 utf-8(默认)编译时,编译器会解释 s0 中的字符,就好像它们已经在 UTF-0 中一样,并且不会发生真正的转换;因为UTF-8 中没有这样的东西,所以字符被损坏了。在d 字符串的构造过程中,同样会发生相同的情况,但是通过代码本身,所以字符被处理为好像它们已经在UTF-8 中,然后推送到相同UTF-8 中的字符串。但它们应该首先从ISO8859_1 解码,然后才编码为UTF-8,所以这就是输出错误的原因。

第二种情况

String s0="P\u00ebrsh\u00ebndetje bot\u00eb!";

原始字符串已经完全在UTF-8 中。因此,显示它的问题会更少。

String d = new String(b1, "UTF8") 不会改变原始字符串; d.equals(s0)true => Përshëndetje botë!

String p =new String(b1, "ISO8859_1") 将原始的UTF-8 字符串转换为ISO8859_1 => Përshëndetje botë!

p.equals("Përshëndetje botë!")true

不知道这里发生了什么以及为什么最后一个正确地获取所有字符:

String s0_iso=new String(b2, "UTF8") => P�rsh�ndetje bot�

String s0_iso=new String(b2, "ISO-8859-1") => Përshëndetje botë!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-07
    • 2015-11-21
    • 2021-06-16
    • 2011-12-11
    • 2012-04-19
    • 1970-01-01
    • 2011-04-22
    相关资源
    最近更新 更多