将ISO8859字符串转换为UTF8?ÄÖÜ => ÃÃ为什么?

7
这段代码有什么问题?我创建了一个ISO8859字符串。所以大部分的ÄÖÜ都是一些加密输出,这没问题。但如何将它们转换回普通字符(UTF8或其他编码)呢?
    String s = new String("Üü?öäABC".getBytes(), "ISO-8859-15");

    System.out.println(s);
    //ÃÃŒ?öÀABC => ok(?)
    System.out.println(new String(s.getBytes(), "ISO-8859-15"));
    //ÃÂÃÅ?öÃâ¬ABC => ok(?)
    System.out.println(new String(s.getBytes(), "UTF-8"));
    //ÃÃŒ?öÀABC => huh?

假设"krypooutput"表示加密函数的输出,为什么要将其转换为"普通字符"。这是不安全的,并且会导致数据丢失。如果需要以人类可读的形式显示数据,请使用十六进制编码或URL编码。 - Vineet Reynolds
1
Java中不存在“ISO8859字符串”的概念。请参阅http://balusc.blogspot.com/2009/05/unicode-how-to-get-characters-right.html。 - axtavt
那么如何将输入的字符串“ÃÃŒ?öÀABC”转换为正常字符串呢?(如果我知道该字符串来自ISO8859文件) - Lissy
1
所以,你有一个IOS8859文件?那么在从中读取字符串时,你需要指定编码方式,例如通过InputStreamReader - axtavt
1
@Lissy:你面临的第一个严重问题是在*.java源文件中使用了非ASCII字符,这是一种幻觉。不幸的是,Java没有指定其源代码文件的编码方式,如果在.java*源文件中使用非ASCII字符,你将会遇到很多麻烦。字符串应该被外部化,使用非ASCII字符的Java程序员在.java注释中应该被枪毙。这在玩具般的环境中是可以接受的,其中只有一个开发人员在一个IDE和一个VCS上工作,并且只有一个操作系统,但是一旦你混合了开发人员,你就会发现痛苦。外部化你的字符串。 - SyntaxT3rr0r
显示剩余4条评论
7个回答

7
我希望这能解决你的问题。
String readable = "äöüÄÖÜßáéíóúÁÉÍÓÚàèìòùÀÈÌÒÙñÑ";

try {
    String unreadable = new String(readable.getBytes("UTF-8"), "ISO-8859-15");
    // unreadable -> äöüÃÃÃÃáéíóúÃÃÃÃÃàèìòùÃÃÃÃÃñÃ
} catch (UnsupportedEncodingException e) {
    // handle error
}

并且:

String unreadable = "äöüÃÃÃÃáéíóúÃÃÃÃÃàèìòùÃÃÃÃÃñÃ";

try {
    String readable = new String(unreadable.getBytes("ISO-8859-15"), "UTF-8");
    // readable -> äöüÄÖÜßáéíóúÁÉÍÓÚàèìòùÀÈÌÒÙñÑ
} catch (UnsupportedEncodingException e) {
    // ...
}

嗨Jooce,我尝试了一下,看起来它运行良好,谢谢你。 - Sundhar

7
一个类似于new String("Üü?öäABC".getBytes(), "ISO-8859-15");的结构几乎总是错误的。
在这里,您正在获取平台默认编码中对应的byte[],并将其重新解释为ISO-8859-15以将其转换回String如果平台默认编码恰好是ISO-8859-15(或足够接近,使得对于此特定的String没有区别,例如ISO-8859-1),那么它是一个无操作(即它没有实际效果)。
在所有其他情况下,它很可能会破坏String如果您尝试“修复”String,则可能为时已晚:如果您必须使用特定编码来读取数据,则应在二进制数据转换为String数据的点处使用它。例如,如果您从InputStream读取,则需要将正确的编码传递给InputStreamReader的构造函数。
“事后补救”问题将会
  1. 更难以做到,并且
  2. 通常不可能(因为使用错误的编码解码byte[]可能是一种破坏性操作)。

4
String s = new String("Üü?öäABC".getBytes(), "ISO-8859-15"); //bug

所有这段代码所做的就是破坏数据。它将UTF-16数据转码为系统编码(无论它是什么),然后获取这些字节,假装它们是有效的ISO-8859-15,并将它们转码为UTF-16。
那么如何将类似于“ÃÃŒ?öÀABC”这样的输入字符串转换为正常字符串呢?(如果我知道该字符串来自ISO8859文件)
执行此操作的正确方法如下:
byte[] iso859_15 = { (byte) 0xc3, (byte) 0xc3, (byte) 0xbc, 0x3f,
  (byte) 0xc3, (byte) 0xb6, (byte) 0xc3, (byte) 0xa4, 0x41, 0x42,
         0x43 };
String utf16 = new String(iso859_15, Charset.forName("ISO-8859-15"));

Java中的字符串始终为UTF-16编码。所有其他编码必须使用byte类型表示。

现在,如果您使用System.out输出结果字符串,那么可能不会正确显示,但这是一个不同的转码问题。例如,Windows控制台默认编码与系统编码不匹配。System.out使用的编码必须与接收数据的设备的编码匹配。您还应该注意确保您正在使用与编辑器相同的编码读取源文件

要了解字符数据处理在不同语言之间的差异,请阅读此文


1
我应该指出,字节数组包含以ISO-8859-15编码的ÃÃŒ?öÀABC,这可能不是OP想要的字符串。以ISO-8859-15编码的Üü?öäABC将是数组{ 0x22, (byte) 0xdc, (byte) 0xfc, 0x3f, (byte) 0xf6, (byte) 0xe4, 0x41, 0x42, 0x43, 0x22 } - McDowell

2

以下是一种简单的使用String输出的方法(我创建了一个方法来实现这个功能):

public static String (String input){
String output = "";
try {
    /* From ISO-8859-1 to UTF-8 */
    output = new String(input.getBytes("ISO-8859-1"), "UTF-8");
    /* From UTF-8 to ISO-8859-1 */
    output = new String(input.getBytes("UTF-8"), "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}
return output;

}

// Example
input = "Música";
output = "Música";

它起作用了!! :)


1
Java字符串在内部始终作为UTF16数组存储(在编译后的类文件中作为UTF8),因此您不能简单地将字符串解释为字节数组。如果您想从特定编码的字符串创建字节数组,必须先转换为该编码:
byte[] b = "Üü?öäABC".getBytes("ISO-8859-15");

System.out.println(new String(b, "ISO-8859-15")); // will be ok
System.out.println(new String(b, "UTF-8")); // will look garbled

1
这个解决方案对我有效,希望能帮到你。
String s1 = "l'épargne";
String s2 = new String(s1.getBytes("iso-8859-1"), "utf8");

0
我想提供扩展字符集,以验证从ISO-8859-1转换为utf-8的字符串。
@Test
public void testEnc() throws UnsupportedEncodingException {
    String isoString = "äö";
    String utfString = new String(isoString.getBytes("ISO-8859-1"), "utf-8");
    boolean validConvertion = containsSpecialCharacter(utfString);
    assertTrue(validConvertion);
}

public boolean containsSpecialCharacter(String str) {
    String[] readable = new String[] { "Ã", "Ã", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "×", "Ø", "Ù", "Ú", "Û", "Ü", "Ã", "Þ", "ß",
            "à", "á", "â", "ã", "ä", "å", "æ", "ç", "è", "é", "ê", "ë", "ì", "í", "î", "ï", "ð", "ñ", "ò", "ó", "ô", "õ", "ö",
            "÷", "ø", "ù", "ú", "û", "ü", "ý", "þ", "ÿ" };
    for (String st : readable) {
        if (str.contains(st)) {
            return true;
        }
    }
    return false;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接