2009-08-13 8 views
5

Ich versuche, einige UTF-8-Zeichenfolgen in Java zu dekodieren. Diese Zeichenfolgen enthalten einige kombinierende Unicode-Zeichen, z. B. CC 88 (Diaresis kombinieren). Die Zeichenfolge scheint in Ordnung, nach http://www.fileformat.info/info/unicode/char/0308/index.htmJava UTF-8 seltsames Verhalten

Aber die Ausgabe nach der Konvertierung in String ist ungültig. Irgendeine Idee?

byte[] utf8 = { 105, -52, -120 }; 
System.out.print("{{"); 
for(int i = 0; i < utf8.length; ++i) 
{ 
    int value = utf8[i] & 0xFF; 
    System.out.print(Integer.toHexString(value)); 
} 
System.out.println("}}"); 
System.out.println(">" + new String(utf8, "UTF-8")); 

Ausgang:

 
    {{69cc88}} 
    >i? 

Antwort

9

Die Konsole, die Sie (zum Beispiel Windows) sind die Ausgabe möglicherweise nicht Unicode-Unterstützung und kann die Zeichen mangle. Die Konsolenausgabe ist keine gute Darstellung der Daten.

Versuchen Sie stattdessen, die Ausgabe in eine Datei zu schreiben, stellen Sie sicher, dass die Codierung im FileWriter korrekt ist, und öffnen Sie dann die Datei in einem Unicode-freundlichen Editor.

Verwenden Sie alternativ einen Debugger, um sicherzustellen, dass die Zeichen Ihren Erwartungen entsprechen. Vertraue der Konsole einfach nicht.

+0

+1: Unter Ubuntu 9.04 in einem Terminal (gnome-terminal) ist die Ausgabe das i mit diaresis, wie Sie es wahrscheinlich erwarten. –

+0

Ich mag dieses Wort "Diärese". Ich muss es vielleicht häufiger im Gespräch verwenden. – skaffman

+1

:) versuchen Sie auch "Umlaut", und Sie werden der Mann des Abends sein. –

4

Der Code ist in Ordnung, aber wie skaffman sagte, dass Ihre Konsole wahrscheinlich nicht das entsprechende Zeichen unterstützt.

sicher zu testen, müssen Sie den Unicode-Wert des Zeichens drucken:

public class Test { 
    public static void main(String[] args) throws Exception { 
     byte[] utf8 = { 105, -52, -120 }; 
     String text = new String(utf8, "UTF-8"); 
     for (int i=0; i < text.length(); i++) { 
      System.out.println(Integer.toHexString(text.charAt(i))); 
     } 
    } 
} 

Dieser druckt 69, 308 - die correct (U + 0069, U + 0308) ist.

4

Sie haben beide Recht. Vielen Dank !!

Hier, wie ich endlich das Problem gelöst, in Eclipse unter Windows:

  • In Run-Konfiguration, Argumente Registerkarte I "-Dfile.encoding=UTF-8" zu den VM Argumenten hinzugefügt
  • In der Run-Konfiguration, Registerkarte Allgemein , stelle ich die Console-Codierung auf UTF-8

Und ich den Code wie folgt geändert:

byte[] utf8 = { 105, -52, -120 }; 
System.out.print("{{"); 
for(int i = 0; i < utf8.length; ++i) 
{ 
    int value = utf8[i] & 0xFF; 
    System.out.print(Integer.toHexString(value)); 
} 
System.out.println("}}"); 

PrintStream sysout = new PrintStream(System.out, true, "UTF-8"); 
sysout.print(">" + new String(utf8, "UTF-8")); 

Ausgang:

 
{{69cc88}} 
> ï 

Dank!

+0

Sie sollten den Schalter "-Dfile.encoding = UTF-8" nicht benötigen, wenn Sie die Daten selbst mit einem PrintStream verschlüsseln möchten. (Das manuelle Festlegen der Eigenschaft "file.encoding" kann für jeden Code problematisch sein, der die Systemcodierung kennen muss.) – McDowell

1

Java codiert nicht unbegründet Unicode-Zeichen in native systemcodierte Bytes, bevor sie in stdout geschrieben werden. Einige Betriebssysteme, wie viele Linux-Distributionen, verwenden UTF-8 als ihren Standardzeichensatz, was nett ist.

Die Dinge unterscheiden sich unter Windows aus einer Reihe von Abwärtskompatibilitätsgründen ein wenig. Die Standard-Systemcodierung ist eine der "ANSI" Codepages und wenn Sie die Standard-Eingabeaufforderung (cmd.exe) öffnen, wird es eine der alten "OEM" DOS-Codepages (obwohl es möglich ist, ANSI und Unicode dort with a bit of work zu erhalten).

Da U + 0308 in keinem der "ANSI" Zeichensätze enthalten ist (wahrscheinlich in Ihrem Fall 1252), wird es als ein Fehlerzeichen (normalerweise ein Fragezeichen) codiert.

Eine Alternative zu Unicode-Enabling alles zu normalize die Kombinationssequenz U + 0069 U + 0308 mit dem Einzelzeichen U + 00EF:

public static void emit(String foo) throws IOException { 
    System.out.println("Literal: " + foo); 
    System.out.print("Hex: "); 
    for (char ch : foo.toCharArray()) { 
     System.out.print(Integer.toHexString(ch & 0xFFFF) + " "); 
    } 
    System.out.println(); 
    } 

    public static void main(String[] args) throws IOException { 
    String foo = "\u0069\u0308"; 
    emit(foo); 
    foo = Normalizer.normalize(foo, Normalizer.Form.NFC); 
    emit(foo); 
    } 

Unter windows-1252, wird dieser Code emittieren:

 
Literal: i? 
Hex: 69 308 
Literal: ï 
Hex: ef