我有一个使用UTF-8编码String的byte[]数组创建.
但是,应该使用其他编码(Windows-1252)创建它.
有没有办法将此String转换回正确的编码?
我知道如果你可以访问原始的字节数组很容易,但是我的情况为时已晚,因为它是由一个封闭的源库提供的.
Joa*_*uer 25
由于似乎对这是否可能存在一些疑惑,我想我需要提供一个广泛的例子.
该问题声称(初始)输入byte[]包含Windows-1252编码数据.我会称之为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.
Run Code Online (Sandbox Code Playgroud)
(如果您的JVM不支持该编码,那么您可以使用ISO-8859-1,因为这三个字母(以及大多数其他字母)在这两个编码中处于相同的位置).
问题继续说明一些其他代码(超出我们的影响力)已经byte[]使用UTF-8编码将其转换为String(我将其称为String is"输入字符串").这String是实现我们目标的唯一输入(如果is可用,那将是微不足道的):
String is = new String(ib, "UTF-8");
System.out.println(is);
Run Code Online (Sandbox Code Playgroud)
这显然会产生错误的输出"B ".
目标是仅用可用产生ib(或正确解码byte[]). is
现在有些人声称从中is获取UTF-8编码的字节将返回一个与初始数组具有相同值的数组:
byte[] utf8Again = is.getBytes("UTF-8");
Run Code Online (Sandbox Code Playgroud)
但是,这会返回两个字符的UTF-8编码,B并且?在重新解释为Windows-1252时肯定会返回错误的结果:
System.out.println(new String(utf8Again, "Windows-1252");
Run Code Online (Sandbox Code Playgroud)
这一行产生输出"B�",这是完全错误的(如果初始数组包含非单词"Bür",它也会产生相同的输出).
因此,在这种情况下,您无法撤消操作,因为信息丢失了.
有是实际上情况下,这种错误的编码可以撤消.当所有可能(或至少发生)的字节序列在该编码中有效时,它更有可能工作.由于UTF-8有几个字节序列只是无效的值,因此您将遇到问题.
les*_*es2 11
我尝试了这个,它出于某种原因起作用
用于修复编码问题的代码(它不能很好地工作,我们很快就会看到):
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);
Run Code Online (Sandbox Code Playgroud)
结果是:
input: …Und ich beweg mich (aber heut nur langsam)
fixed: …Und ich beweg mich (aber heut nur langsam)
Run Code Online (Sandbox Code Playgroud)
这是另一个例子:
input: Waun da wuan ned wa (feat. Wolfgang Kühn)
fixed: Waun da wuan ned wa (feat. Wolfgang Kühn)
Run Code Online (Sandbox Code Playgroud)
这是正在发生的事情以及为什么上面的技巧似乎有效:
现在,当我们试图"逆转"这个过程时,会发生以下情况:
// 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);
Run Code Online (Sandbox Code Playgroud)
上面的编码修复代码有效,但对于以下字符无效:
(假设唯一的字符使用Windows 1252中的1个字节字符):
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
Run Code Online (Sandbox Code Playgroud)
它适用于某些角色,例如:
Þ 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 ç
Run Code Online (Sandbox Code Playgroud)
注意 - 我原本认为这与你的问题有关(当我自己也在做同样的事情时,我想我会分享我所学到的东西),但似乎我的问题略有不同.也许这会帮助别人.