我有一个使用UTF-8编码从byte[]
数组创建的String
,但实际上应该使用另一种编码(Windows-1252)创建。
是否有方法将此字符串转换回正确的编码?
如果你拥有原始的字节数组,那么做起来很容易,但在我的情况下,这是不可能的,因为它是由一个封闭源代码库提供的。
由于似乎有些混淆,关于这个是否可能,我认为需要提供一个详细的例子。
问题声称(初始)输入是包含Windows-1252编码数据的byte[]
。 我将称之为byte[] ib
(“初始字节”)。
对于此示例,我将选择德语单词“Bär”(意思是熊)作为输入:
byte[] ib = new byte[] { (byte) 0x42, (byte) 0xE4, (byte) 0x72 };
String correctString = new String(ib, "Windows-1252");
assert correctString.charAt(1) == '\u00E4'; //verify that the character was correctly decoded.
如果你的JVM不支持该编码,那么你可以使用ISO-8859-1,因为这两种编码中这三个字母(以及大多数其他字母)在相同位置上。
问题继续说明,一些其他代码(超出我们的影响范围)已经使用UTF-8编码将该byte[]
转换为String
(我将称之为“输入字符串”),该String
是实现我们目标的唯一输入(如果ib
可用,这将是微不足道的):
String is = new String(ib, "UTF-8");
System.out.println(is);
这显然会产生不正确的输出“B�”。
目标是只使用is
来产生ib
(或其正确解码的byte[]
)。
现在有些人声称从is
中获取UTF-8编码的字节将返回一个与初始数组具有相同值的数组:
byte[] utf8Again = is.getBytes("UTF-8");
但是这会返回两个字符 B
和 �
的 UTF-8 编码,当重新解释为 Windows-1252 时肯定会得到错误的结果:
System.out.println(new String(utf8Again, "Windows-1252");
这行代码会输出“B�”,这完全是错误的(如果初始数组包含非单词“Bür”,也将产生相同的输出)。
因此,在这种情况下,您无法撤消操作,因为有一些信息已经丢失了。
实际上存在一些可以纠正这种错误编码的情况。如果在编码中所有可能的(或至少出现过的)字节序列都是有效的,那么更有可能成功。由于UTF-8有几个字节序列是无效值,所以您将会遇到问题。
final Charset fromCharset = Charset.forName("windows-1252");
final Charset toCharset = Charset.forName("UTF-8");
String fixed = new String(input.getBytes(fromCharset), toCharset);
System.out.println(input);
System.out.println(fixed);
input: …Und ich beweg mich (aber heut nur langsam)
fixed: …Und ich beweg mich (aber heut nur langsam)
input: Waun da wuan ned wa (feat. Wolfgang Kühn)
fixed: Waun da wuan ned wa (feat. Wolfgang Kühn)
// we start with this garbage, two characters we don't want!
String input = "ü";
final Charset cp1252 = Charset.forName("windows-1252");
final Charset utf8 = Charset.forName("UTF-8");
// lets convert it to bytes in windows-1252:
// this gives you 2 bytes: c3 bc
// "Ã" ==> c3
// "¼" ==> bc
bytes[] windows1252Bytes = input.getBytes(cp1252);
// but in utf-8, c3 bc is "ü"
String fixed = new String(windows1252Bytes, utf8);
System.out.println(input);
System.out.println(fixed);
char utf-8 bytes | string decoded as cp1252 --> as cp1252 bytes
” e2 80 9d | â€� e2 80 3f
Á c3 81 | Ã� c3 3f
Í c3 8d | Ã� c3 3f
Ï c3 8f | Ã� c3 3f
Рc3 90 | � c3 3f
Ý c3 9d | Ã� c3 3f
它对某些字符确实有效,例如这些:
Þ c3 9e | Þ c3 9e Þ
ß c3 9f | ß c3 9f ß
à c3 a0 | Ã c3 a0 à
á c3 a1 | á c3 a1 á
â c3 a2 | â c3 a2 â
ã c3 a3 | ã c3 a3 ã
ä c3 a4 | ä c3 a4 ä
å c3 a5 | Ã¥ c3 a5 å
æ c3 a6 | æ c3 a6 æ
ç c3 a7 | ç c3 a7 ç
注意 - 我最初认为这与您的问题有关(而且因为我自己也在做同样的事情,所以我想分享一下我所学到的东西),但似乎我的问题略有不同。也许这会帮助其他人。