2010-05-04 25 views
10

Sto riscontrando qualche problema nel recuperare testo francese da convertire in UTF8 in modo che possa essere visualizzato correttamente, in una console, in un file di testo o in un elemento della GUI.Codifica caratteri UTF-8 in Java

La stringa originale è

HANDICAP╔ES

, che si suppone essere

handicapées

Ecco un frammento di codice che mostra come sto usando il driver jackcess database a leggere nel file Acccess MDB in un ambiente Eclipse/Linux.

Database database = Database.open(new File(filepath)); 
Table table = database.getTable(tableName, true); 
Iterator rowIter = table.iterator(); 
while (rowIter.hasNext()) { 
    Map<String, Object> row = this.rowIter.next(); 
    // convert fields to UTF 
    Map<String, Object> rowUTF = new HashMap<String, Object>(); 
    try { 
     for (String key : row.keySet()) { 
      Object o = row.get(key); 
      if (o != null) { 
       String valueCP850 = o.toString(); 
       // String nameUTF8 = new String(valueCP850.getBytes("CP850"), "UTF8"); // does not work! 
       String valueISO = new String(valueCP850.getBytes("CP850"), "ISO-8859-1"); 
       String valueUTF8 = new String(valueISO.getBytes(), "UTF-8"); // works! 
       rowUTF.put(key, valueUTF8); 
      } 
     } 
    } catch (UnsupportedEncodingException e) { 
     System.err.println("Encoding exception: " + e); 
    } 
} 

Nel codice vedrete dove voglio convertire direttamente in UTF-8, che non sembra funzionare, quindi devo fare una doppia conversione. Si noti inoltre che non sembra essere un modo per specificare il tipo di codifica quando si utilizza il driver jackcess.

Grazie, Cam

+1

Questo non è UTF-8 ma piuttosto CP850. – Joey

+0

Stai dicendo che la stringa originale è CP850? Mi rendo conto che la stringa originale non era UTF-8, anche se non ero sicuro di quale esatta codifica. È UTF-8 che sto cercando di convertirlo in modo che venga visualizzato correttamente. Ed è a mia conoscenza che il carattere É è supportato da UTF-8. Grazie. – cambo

+3

'╔' è ciò che ottieni quando prendi' É' in CP1252 e lo interpreti come CP850. – Joey

risposta

9

Nuova analisi, basata su nuove informazioni.
Sembra che il problema sia dovuto alla codifica del testo prima dello che è stato memorizzato nel DB di accesso. Sembra che sia stato codificato come ISO-8859-1 o Windows-1252, ma decodificato come cp850, risultando nella stringa HANDICAP╔ES memorizzata nel DB.

Dopo aver recuperato correttamente quella stringa dal DB, si sta tentando di invertire l'errore di codifica originale e ripristinare la stringa come avrebbe dovuto essere memorizzata: HANDICAPÉES. E si sta realizzando che con questa linea:

String valueISO = new String(valueCP850.getBytes("CP850"), "ISO-8859-1"); 

getBytes("CP850") converte il carattere al valore di byte 0xC9, e il costruttore String decodifica che, secondo la norma ISO-8859-1, con conseguente carattere É. La riga successiva:

String valueUTF8 = new String(valueISO.getBytes(), "UTF-8"); 

... non fa nulla. getBytes() codifica la stringa nella codifica predefinita della piattaforma, che è UTF-8 sul tuo sistema Linux. Quindi il costruttore String lo decodifica con la stessa codifica. Elimina quella linea e dovresti comunque ottenere lo stesso risultato.

Più precisamente, il tentativo di creare una "stringa UTF-8" è stato fuorviato. Non è necessario preoccuparsi della codifica delle stringhe di Java: sono sempre UTF-16. Quando inserisci del testo in un'app Java, devi solo assicurarti di decodificarlo con la codifica corretta.

E se la mia analisi è corretta, il tuo driver di accesso è che lo decodifica correttamente; il problema è dall'altra parte, probabilmente prima che il DB entri in scena. Questo è ciò che è necessario correggere, perché non è possibile contare su tale trucco new String(getBytes()) in tutti i casi.


analisi originale, sulla base di non informazioni.: -/
Se si vede HANDICAP╔ES sulla console, probabilmente non ci sono problemi.Dato questo codice:

System.out.println("HANDICAPÉES"); 

La JVM converte il (Unicode) stringa per la codifica di default della piattaforma, windows-1252, prima di inviarlo alla console. Quindi la console decodifica utilizzando la sua codifica predefinita 0, che risulta essere cp850. Quindi la console lo mostra male, ma è normale. Se si desidera che venga visualizzato correttamente, è possibile modificare la codifica della console con questo comando:

CHCP 1252 

Per visualizzare la stringa in un elemento GUI, come ad esempio un JLabel, non devi fare nulla di speciale. Assicurati di utilizzare un carattere che possa visualizzare tutti i caratteri, ma questo non dovrebbe essere un problema per il francese.

Per quanto riguarda la scrittura su un file, basta specificare la codifica desiderata quando si crea il Writer:

OutputStreamWriter osw = new OutputStreamWriter(
    new FileOutputStream("myFile.txt"), "UTF-8"); 
+0

Credo che avrei dovuto essere più chiaro riguardo al mio ambiente di sviluppo. Per lo sviluppo, sto usando Eclipse su una macchina Ubuntu Linux. Ottengo gli stessi risultati sia che lo esegua dalla console Eclipse o attraverso una normale console di terminale. Utilizziamo API Java jackcess per leggere il file di database MDB di Access. Non sembra che sia possibile specificare una codifica predefinita per il driver jackcess, quindi devo eseguire la conversione come descritto sopra. Ho provato a esportare la stringa direttamente in un elemento della GUI (JLabel, JTextField), ma non è stato di alcun aiuto. – cambo

+0

Sì, questo sembra essere un problema piuttosto esotico, di cui non c'era alcun suggerimento nella domanda originale. Potrebbe essere utile se potessimo vedere il codice effettivo che stai utilizzando per recuperare i dati. E non provare a metterlo in un commento: hai già visto quanto funziona bene. Modifica la domanda e mettila lì. –

+0

Ok, ho modificato la domanda per mostrare un esempio del codice che sto usando per recuperare i dati. Grazie. – cambo

8
String s = "HANDICAP╔ES"; 
System.out.println(new String(s.getBytes("CP850"), "ISO-8859-1")); // HANDICAPÉES 

Questo mostra il valore di stringa corretta. Ciò significa che è stato originariamente codificati/decodificati con ISO-8859-1 e quindi in modo non corretto codificati con CP850 (originariamente CP1252 aka ANSI di Windows come sottolineato in un commento è infatti possibile dal momento che il É ha lo stesso valore di codice lì come in ISO-8859- 1).

Allineare l'ambiente e le pipeline binarie per utilizzare tutte le codifiche di un solo carattere. Non puoi e non devi convertire tra di loro. Si rischierebbe di perdere informazioni nella gamma non ASCII in questo modo.

Nota: NON utilizzare lo snippet di codice precedente per "risolvere" il problema! Non sarebbe la soluzione giusta.


Aggiornamento: si è apparentemente ancora alle prese con il problema. Ripeto le parti importanti della risposta:

  1. Allineare il vostro ambiente e oleodotti binari da utilizzare tutto la stessa codifica dei caratteriuno e .

  2. Puoi non e dovrebbe non convertire tra di loro. Rischiate di perdere informazioni nella gamma non ASCII in questo modo.

  3. Do NON utilizzare lo snippet di codice precedente per "risolvere" il problema! Questa non sarebbe la soluzione destra .

Per risolvere il problema è necessario scegliere la codifica dei caratteri X che si desidera utilizzare in tutta l'applicazione. Suggerisco UTF-8. Aggiorna MS Access per utilizzare la codifica X. Aggiorna il tuo ambiente di sviluppo per utilizzare la codifica X. Aggiorna i lettori e i writer java.io nel codice per utilizzare la codifica X. Aggiorna il tuo editor per leggere/scrivere i file con la codifica X. Aggiorna l'interfaccia utente dell'applicazione per utilizzare codifica X. Do non usa Y o Z o qualsiasi altra cosa ad un certo punto. Se i caratteri sono già corretti in alcuni datastore (accesso MS, file, ecc. Non usare Java per questo.

Se si sta effettivamente utilizzando il "prompt dei comandi" come interfaccia utente, allora si è effettivamente persi. Non supporta UTF-8. Come suggerito nei commenti e nell'articolo collegato nei commenti, è necessario creare un'applicazione Swing anziché fare affidamento sull'ambiente del prompt dei comandi limitato.

+0

Grazie per questa risposta. I dati che sto ricevendo sono in un database di Access, quindi non ho il controllo su come è stato originariamente codificato. Credo di aver bisogno di leggerlo e convertirlo nel formato corretto prima di fare qualsiasi cosa. Inoltre, stiamo cercando di standardizzare e utilizzare UTF-8 per tutto nella nostra applicazione. UTF-8 non supporta questi caratteri? – cambo

+2

È necessario istruire il driver JDBC e/o il database per utilizzare la codifica corretta (quella che sta utilizzando il database stesso!). UTF-8 supporta certamente quei caratteri, ma con una rappresentazione binaria diversa, se capisci cosa intendo. I caratteri sono cioè -come tutto- trasferiti come byte. Semplicemente perché i computer non capiscono niente altro. [Questo articolo] (http://balusc.blogspot.com/2009/05/unicode-how-to-get-characters-right.html) può aiutare di più nella comprensione del problema sotto i cofani. – BalusC

+0

Grazie per le informazioni e per il collegamento, questo è un ottimo articolo! – cambo

-1

Utilizzando "ISO-8859-1" mi ha aiutato a trattare con il charactes francesi.

0

È possibile specificare la codifica quando si stabilisce la connessione. In questo modo è stato perfetto e risolvere il mio problema di codifica:

DatabaseImpl open = DatabaseImpl.open(new File("main.mdb"), true, null, Database.DEFAULT_AUTO_SYNC, java.nio.charset.Charset.availableCharsets().get("windows-1251"), null, null); 
    Table table = open.getTable("FolderInfo");