2010-05-04 42 views
10

Tengo algunos problemas para convertir un poco de texto francés a UTF8 para que se pueda mostrar correctamente, ya sea en una consola, archivo de texto o en un elemento GUI.Codificación de caracteres UTF-8 en Java

La cadena original es

HANDICAP╔ES

que se supone que es

handicapées

Aquí es un fragmento de código que muestra cómo estoy usando el controlador de base de datos para leer jackcess en el archivo Acccess MDB en un entorno 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); 
    } 
} 

En el código verá donde quiero convertir directamente a UTF8, lo que no parece funcionar, por lo que tengo que hacer un doble conversión. También tenga en cuenta que no parece haber una manera de especificar el tipo de codificación cuando se utiliza el controlador de jackcess.

Gracias, Cam

+1

Eso no es UTF-8, sino más bien CP850. – Joey

+0

¿Estás diciendo que la cadena original es CP850? Me doy cuenta de que la cadena original no era UTF-8, aunque no estaba seguro de qué codificación exacta. Es UTF-8 que estoy tratando de convertir para que se muestre correctamente. Y entiendo que el personaje É es compatible con UTF-8. Gracias. – cambo

+3

'╔' es lo que obtiene cuando toma' É' en CP1252 y lo interpreta como CP850. – Joey

Respuesta

9

Nuevo análisis, basado en nueva información.
Parece que su problema es con la codificación del texto antes de que se almacenó en Access DB. Parece que se codificó como ISO-8859-1 o Windows-1252, pero se decodificó como cp850, por lo que la cadena HANDICAP╔ES se almacena en el DB.

Al haber recuperado correctamente esa cadena de la base de datos, ahora está intentando revertir el error de codificación original y recuperar la cadena como debería haberse almacenado: HANDICAPÉES. Y que está logrando que con esta línea:

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

getBytes("CP850") convierte el carácter al valor de byte 0xC9, y el constructor de String decodifica que de acuerdo a la norma ISO-8859-1, lo que resulta en el carácter É. La siguiente línea:

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

... no hace nada. getBytes() codifica la cadena en la codificación predeterminada de la plataforma, que es UTF-8 en su sistema Linux. Entonces el constructor String lo decodifica con la misma codificación. Elimina esa línea y aún deberías obtener el mismo resultado.

Más al punto, su intento de crear una "cadena UTF-8" fue erróneo. No necesita preocuparse por la codificación de las cadenas de Java, siempre son UTF-16. Cuando traes texto a una aplicación Java, solo necesitas asegurarte de decodificarlo con la codificación correcta.

Y si mi análisis es correcto, su controlador de acceso es decodificándolo correctamente; el problema está en el otro extremo, posiblemente antes de que el DB aparezca en escena. Eso es lo que necesita reparar, porque ese truco new String(getBytes()) no se puede contar para que funcione en todos los casos.


análisis original, basado en ninguna información.: -/
Si está viendo HANDICAP╔ES en la consola, probablemente no haya ningún problema.Teniendo en cuenta este código:

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

La JVM convierte la (Unicode) cadena a la plataforma de codificación predeterminada, Windows-1252, antes de enviarlo a la consola. Luego, la consola decodifica eso usando su propia codificación , que resulta ser cp850. Entonces la consola lo muestra mal, pero eso es normal. Si quieres que se muestre correctamente, puede cambiar la codificación de la consola con este comando:

CHCP 1252 

para mostrar la cadena en un elemento de interfaz gráfica de usuario, como por ejemplo un JLabel, usted no tiene que hacer nada especial. Solo asegúrate de usar una fuente que pueda mostrar todos los caracteres, pero eso no debería ser un problema para el francés.

En cuanto a escribir en un archivo, basta con especificar la codificación deseada cuando se crea al escritor:

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

Supongo que debería haber sido más claro sobre mi entorno de desarrollo. Para el desarrollo, estoy usando Eclipse en una máquina Ubuntu Linux. Obtengo los mismos resultados si lo ejecuto desde la consola de Eclipse o a través de una consola de terminal normal. Estamos utilizando la API javascript de jackcess para leer el archivo de base de datos Access MDB. Parece que no hay forma de especificar una codificación predeterminada para el controlador de jackcess, así que tengo que hacer la conversión como describí anteriormente. Intenté sacar la cadena directamente en un elemento GUI (JLabel, JTextField) pero eso tampoco ayudó. – cambo

+0

Sí, esto parece ser un problema bastante exótico, del cual no había ninguna pista en la pregunta original. Podría ser útil si pudiéramos ver el código real que está utilizando para recuperar los datos. Y no trates de poner eso en un comentario, ya has visto lo bien que funciona. Edita la pregunta y ponla allí. –

+0

Ok, he editado la pregunta para mostrar una muestra del código que estoy usando para recuperar los datos. Gracias. – cambo

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

Esto demuestra el valor de cadena correcta. Esto significa que era originalmente codificada/descodificada con ISO-8859-1 y luego incorrectamente codificado con CP850 (originalmente CP1252 aka de Windows ANSI como se ha señalado en un comentario es, en efecto, también es posible ya que el É tiene el mismo punto de código allí como en la norma ISO-8859- 1).

Alinea tu entorno y las tuberías binarias para utilizar la codificación de un solo y el mismo carácter. No puede y no debe convertir entre ellos. Corre el riesgo de perder información en el rango no ASCII de esa manera.

Nota: NO utilice el fragmento de código anterior para "solucionar" el problema. Esa no sería la solución correcta.


actualización: usted está al parecer todavía luchando con el problema. Voy a repetir las partes importantes de la respuesta:

  1. Alinee el medio ambiente y las tuberías binarios para usar toda launo y misma codificación de caracteres.

  2. Puede no y debe no convertir entre ellos. Correría el riesgo de perdiendo información en el rango no ASCII de esa manera.

  3. Do ¡NO utilice el fragmento de código de arriba para "solucionar" el problema! Esa no sería la solución right.

Para solucionar el problema, debe elegir la codificación de caracteres X que desea utilizar durante toda la aplicación. Sugiero UTF-8. Actualice el acceso de MS para usar la codificación X. Actualice su entorno de desarrollo para usar la codificación X. Actualice los lectores y escritores java.io en su código para usar la codificación X. Actualice su editor para leer/escribir archivos con la codificación X. Actualice la interfaz de usuario de la aplicación codificando X. Do no use Y o Z o lo que sea en algún momento. Si los caracteres son ya corruptos en algún almacén de datos (MS Access, archivos, etc.), entonces necesita repararlo reemplazando manualmente los caracteres allí mismo en el almacén de datos. No use Java para esto.

Si realmente está utilizando el "símbolo del sistema" como interfaz de usuario, entonces en realidad está perdido. No es compatible con UTF-8. Tal como se sugiere en los comentarios y en el artículo vinculado en los comentarios, debe crear una aplicación Swing en lugar de confiar en el entorno de solicitud de comando restringido.

+0

Gracias por esta respuesta. Los datos que recibo están en una base de datos de Access, por lo que no tengo control sobre cómo se codificó originalmente. Supongo que necesito leerlo y convertirlo al formato adecuado antes de hacer cualquier cosa. Además, estamos tratando de estandarizar y usar UTF-8 para todo en nuestra aplicación. ¿UTF-8 no es compatible con estos personajes? – cambo

+2

Debería indicar al controlador JDBC y/o la base de datos que utilicen la codificación adecuada (¡la que la base de datos está utilizando!). UTF-8 sin duda admite esos personajes, pero con una representación binaria diferente, si entiendes lo que quiero decir. Los personajes se llaman, como todo, transferidos como bytes. Simplemente porque las computadoras no entienden nada más. [Este artículo] (http://balusc.blogspot.com/2009/05/unicode-how-to-get-characters-right.html) puede ayudar más a comprender el problema bajo los capós. – BalusC

+0

Gracias por la información y el enlace, ¡es un excelente artículo! – cambo

-1

El uso de "ISO-8859-1" me ayudó a hacer frente a la charactes franceses.

0

Puede especificar la codificación al establecer la conexión. De esta manera fue perfecto y resolver mi problema de codificación:

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"); 
Cuestiones relacionadas