2009-03-17 16 views
56

J'essaye de convertir une chaîne encodée en Java en UTF-8 en ISO-8859-1. Dites par exemple, dans la chaîne 'âabcd' 'est représenté dans ISO-8859-1 par E2. En UTF-8, il est représenté par deux octets. C3 A2 Je crois. Lorsque je fais un getbytes (encodage) et ensuite créer une nouvelle chaîne avec les octets dans l'encodage ISO-8859-1, j'obtiens deux caractères différents. Ã ¢. Y a-t-il un autre moyen de faire cela de façon à garder le même caractère, c'est-à-dire, abcd?Convertir UTF-8 en ISO-8859-1 en Java - comment le garder en octet unique

Répondre

29
byte[] iso88591Data = theString.getBytes("ISO-8859-1"); 

Fait l'affaire. De votre description, il semble que vous essayez de "stocker une chaîne ISO-8859-1". Les objets String en Java sont toujours codés implicitement en UTF-16. Il n'y a aucun moyen de changer cet encodage. Ce que vous pouvez faire, 'bien que ce soit d'obtenir les octets qui constituent un autre codage de celui-ci (en utilisant la méthode .getBytes() comme indiqué ci-dessus).

+0

Merci, cela m'a aidé à résoudre le problème lors de la création d'un fichier: ma chaîne de nom de fichier contient un caractère de saut de ligne que je ne pouvais pas remarquer jusqu'à ce que j'ai imprimé la chaîne dans le journal comme ceci: 'string = new String (string.getBytes (" UTF-16 "));' 'Log.d (TAG, chaîne);' et j'ai vu le caractère supplémentaire là –

+0

Merci d'avoir spécifié que "les objets String en Java sont toujours implicitement encodés en UTF-16" - cela a résolu un problème que je énéralement utile à savoir! –

92

Si vous avez affaire à codages de caractères autres que UTF-16, vous ne devriez pas utiliser java.lang.String ou la char primitive - vous ne devriez utiliser byte[] des tableaux ou des objets ByteBuffer. Ensuite, vous pouvez utiliser java.nio.charset.Charset pour convertir entre encodages:

Charset utf8charset = Charset.forName("UTF-8"); 
Charset iso88591charset = Charset.forName("ISO-8859-1"); 

ByteBuffer inputBuffer = ByteBuffer.wrap(new byte[]{(byte)0xC3, (byte)0xA2}); 

// decode UTF-8 
CharBuffer data = utf8charset.decode(inputBuffer); 

// encode ISO-8559-1 
ByteBuffer outputBuffer = iso88591charset.encode(data); 
byte[] outputData = outputBuffer.array(); 
+0

Merci beaucoup .. Vraiment utile - Luckylak –

+4

Oui vraiment bonne remarque. En Java, String est lui-même codé en UTF-16. Toujours. Cela n'a aucun sens de penser à des chaînes codées dans quelque chose d'autre. Au lieu de cela, vous avez des données brutes (octets) qui représentent du texte dans certains encodages. Ensuite, vous décoderez (en utilisant un peu d'encodage) en String (en UTF-16), ou en String en bytes. Upvoted! –

+0

@Adam Rosenfield: Byte [] ==> octet [] – AndrewBourgeois

7

À partir d'un ensemble d'octets qui codent pour une chaîne en utilisant UTF-8, crée une chaîne à partir de ces données, puis obtenir quelques octets codant pour la chaîne dans une autre encodage:

byte[] utf8bytes = { (byte)0xc3, (byte)0xa2, 0x61, 0x62, 0x63, 0x64 }; 
    Charset utf8charset = Charset.forName("UTF-8"); 
    Charset iso88591charset = Charset.forName("ISO-8859-1"); 

    String string = new String (utf8bytes, utf8charset); 

    System.out.println(string); 

    // "When I do a getbytes(encoding) and " 
    byte[] iso88591bytes = string.getBytes(iso88591charset); 

    for (byte b : iso88591bytes) 
     System.out.printf("%02x ", b); 

    System.out.println(); 

    // "then create a new string with the bytes in ISO-8859-1 encoding" 
    String string2 = new String (iso88591bytes, iso88591charset); 

    // "I get a two different chars" 
    System.out.println(string2); 

cette cordes sorties et les correctement ISO88591 octets:

âabcd 
e2 61 62 63 64 
âabcd 

Ainsi, votre tableau d'octets n'a pas été associé à la ENCOD correcte ING:

String failString = new String (utf8bytes, iso88591charset); 

    System.out.println(failString); 

Sorties

âabcd 

(soit que, ou vous venez d'écrire l'UTF8 octets dans un fichier et de les lire ailleurs comme ISO88591)

-3

evict non caractères ISO-8859-1 , sera remplacé par '?' (avant l'envoi à un DB ISO-8859-1 par exemple):

utf8String = new String (utf8String.getBytes(), "ISO-8859-1");

+4

Remplacer tous les caractères non-ASCII par '?' Semble une solution terrible quand il est possible de convertir la chaîne sans les perdre. – s4y

0

Si vous avez le codage correct dans la chaîne, vous n'avez pas besoin de faire plus pour obtenir les octets pour un autre encodage.

public static void main(String[] args) throws Exception { 
    printBytes("â"); 
    System.out.println(
      new String(new byte[] { (byte) 0xE2 }, "ISO-8859-1")); 
    System.out.println(
      new String(new byte[] { (byte) 0xC3, (byte) 0xA2 }, "UTF-8")); 
} 

private static void printBytes(String str) { 
    System.out.println("Bytes in " + str + " with ISO-8859-1"); 
    for (byte b : str.getBytes(StandardCharsets.ISO_8859_1)) { 
     System.out.printf("%3X", b); 
    } 
    System.out.println(); 
    System.out.println("Bytes in " + str + " with UTF-8"); 
    for (byte b : str.getBytes(StandardCharsets.UTF_8)) { 
     System.out.printf("%3X", b); 
    } 
    System.out.println(); 
} 

Sortie:

Bytes in â with ISO-8859-1 
E2 
Bytes in â with UTF-8 
C3 A2 
â 
â 
0

Pour les fichiers encodage ...

public class FRomUtf8ToIso { 
     static File input = new File("C:/Users/admin/Desktop/pippo.txt"); 
     static File output = new File("C:/Users/admin/Desktop/ciccio.txt"); 


    public static void main(String[] args) throws IOException { 

     BufferedReader br = null; 

     FileWriter fileWriter = new FileWriter(output); 
     try { 

      String sCurrentLine; 

      br = new BufferedReader(new FileReader(input)); 

      int i= 0; 
      while ((sCurrentLine = br.readLine()) != null) { 
       byte[] isoB = encode(sCurrentLine.getBytes()); 
       fileWriter.write(new String(isoB, Charset.forName("ISO-8859-15"))); 
       fileWriter.write("\n"); 
       System.out.println(i++); 
      } 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      try { 
       fileWriter.flush(); 
       fileWriter.close(); 
       if (br != null)br.close(); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
     } 

    } 


    static byte[] encode(byte[] arr){ 
     Charset utf8charset = Charset.forName("UTF-8"); 
     Charset iso88591charset = Charset.forName("ISO-8859-15"); 

     ByteBuffer inputBuffer = ByteBuffer.wrap(arr); 

     // decode UTF-8 
     CharBuffer data = utf8charset.decode(inputBuffer); 

     // encode ISO-8559-1 
     ByteBuffer outputBuffer = iso88591charset.encode(data); 
     byte[] outputData = outputBuffer.array(); 

     return outputData; 
    } 

} 
0

En plus de la réponse d'Adam Rosenfield, je voudrais ajouter que ByteBuffer.array() retours tableau d'octets sous-jacente de la mémoire tampon, qui n'est pas forcément "coupé" jusqu'au dernier caractère.Manipulation supplémentaire sera nécessaire, tels que ceux mentionnés dans this réponse; en particulier:

byte[] b = new byte[bb.remaining()] 
bb.get(b); 
1

Voici ce que je avais besoin:

public static byte[] encode(byte[] arr, String fromCharsetName) { 
    return encode(arr, Charset.forName(fromCharsetName), Charset.forName("UTF-8")); 
} 

public static byte[] encode(byte[] arr, String fromCharsetName, String targetCharsetName) { 
    return encode(arr, Charset.forName(fromCharsetName), Charset.forName(targetCharsetName)); 
} 

public static byte[] encode(byte[] arr, Charset sourceCharset, Charset targetCharset) { 

    ByteBuffer inputBuffer = ByteBuffer.wrap(arr); 

    CharBuffer data = sourceCharset.decode(inputBuffer); 

    ByteBuffer outputBuffer = targetCharset.encode(data); 
    byte[] outputData = outputBuffer.array(); 

    return outputData; 
}