2010-05-19 23 views
14

tengo que manejar este escenario en Java:eliminar no UTF-8 caracteres de XML con codificación declarada = UTF-8 - Java

Estoy recibiendo una solicitud en forma XML desde un cliente con codificación declarada = utf-8. Desafortunadamente, puede contener no caracteres UTF-8 y existe un requisito para eliminar estos caracteres del xml de mi lado (herencia).

Consideremos un ejemplo en el que este XML no válido contiene £ (libra).

1) Obtengo xml como java String con £ en él (no tengo acceso a la interfaz en este momento, pero probablemente obtenga xml como una cadena java). ¿Puedo usar replaceAll (£, "") para deshacerme de este personaje? ¿Algún problema potencial?

2) Obtengo xml como una matriz de bytes. ¿Cómo puedo manejar esta operación de forma segura en ese caso?

+3

Su pregunta es confusa. La libra es un personaje válido UTF-8. Además, UTF-8 cubre prácticamente todos los personajes que el mundo conoce. ¿Podrías publicar algunos ejemplos del mundo real? ¿No quieres decir que quieres deshacerte de los personajes que no son ASCII? – BalusC

+2

Supongo que recibirá XML que dice ser UTF-8, pero en realidad es Windows-1252, ISO 8859-1 más o menos. Eso haría que cualquier carácter no ASCII sea inválido porque está codificado incorrectamente. ¿El requisito es explícitamente eliminar esos caracteres, o más bien corregir los errores XML (que presumiblemente se eliminan eliminando los caracteres ofensivos)? En el caso de este último, debería poder convertir su entrada a UTF-8 antes de analizarla, suponiendo que su cliente siempre usa la misma codificación (incorrecta). No conozco suficiente Java para decirte cómo hacerlo. – mercator

+0

Tenga en cuenta que debe hacer esto _NOT_ utilizando herramientas XML, porque el analizador puede terminar cuando la entrada no es 100% correcta. –

Respuesta

22

1) Obtengo xml como java String con £ en él (no tengo acceso a la interfaz en este momento, pero probablemente obtenga xml como una cadena java). ¿Puedo usar replaceAll (£, "") para deshacerme de este personaje?

Estoy asumiendo que más bien quiere decir que usted quiere deshacerse de los no ASCII caracteres, ya que estamos hablando de un lado "legado". Usted puede deshacerse de cualquier cosa fuera de la printable ASCII range utilizando la siguiente expresión regular:

string = string.replaceAll("[^\\x20-\\x7e]", ""); 

2) consigo XML como una matriz de bytes - cómo manejar esta operación de forma segura en ese caso?

Necesitas envolver el byte[] en un ByteArrayInputStream, por lo que se puede leer en un flujo de caracteres codificados UTF-8 utilizando InputStreamReader el que se especifica la codificación y luego usar un BufferedReader para leer línea por línea.

E.g.

BufferedReader reader = null; 
try { 
    reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes), "UTF-8")); 
    for (String line; (line = reader.readLine()) != null;) { 
     line = line.replaceAll("[^\\x20-\\x7e]", ""); 
     // ... 
    } 
    // ... 
+0

Gracias mucho !! mi problema era diferente pero esto terminó mi miseria de 2 días :) – HitchHiker

17

UTF-8 es una codificación; Unicode es un conjunto de caracteres. Pero el símbolo GBP está definitivamente en el conjunto de caracteres Unicode y, por lo tanto, es ciertamente representable en UTF-8.

Si, de hecho, decir UTF-8, y en realidad se está tratando de eliminar las secuencias de bytes que no son la codificación válida de un carácter en UTF-8, entonces ...

CharsetDecoder utf8Decoder = Charset.forName("UTF-8").newDecoder(); 
utf8Decoder.onMalformedInput(CodingErrorAction.IGNORE); 
utf8Decoder.onUnmappableCharacter(CodingErrorAction.IGNORE); 
ByteBuffer bytes = ...; 
CharBuffer parsed = utf8Decoder.decode(bytes); 
... 
3

me enfrenté el mismo problema durante la lectura de archivos de un directorio local y probado esto:

BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "UTF-8")); 
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); 
Document xmlDom = db.parse(new InputSource(in)); 

puede que tenga que utilizar el flujo de entrada a la red en lugar de FileInputStream.

- Kapil

7
"test text".replaceAll("[^\\u0000-\\uFFFF]", ""); 

Este código elimina todos los caracteres de 4 bytes utf8 de cadena.Esto puede ser necesario para algunos propósitos al hacer Mysql innodb entrada varchar

1

Tenga en cuenta que el primer paso debe ser que le pregunte al creador del XML (que es muy probablemente un generador XML "solo imprimir datos") para garantizar que su XML es correcto antes de enviarte. La prueba más simple posible si usan Windows es pedirles que lo vean en Internet Explorer y que vean el error de análisis en el primer carácter ofensivo.

Mientras que solucionar esto, simplemente hay que escribir un pequeño programa que cambia la parte de cabecera para declarar que la codificación ISO-8859-1 lugar:

<?xml version="1.0" encoding="iso-8859-1" ?> 

y dejar el resto intacto.

1

Una vez que convierte la matriz de bytes a Cadena en la máquina Java, obtendrá (por defecto en la mayoría de las máquinas) una cadena codificada en UTF-16. La solución adecuada para deshacerse de caracteres UTF-8 no es con el siguiente código:

String[] values = {"\\xF0\\x9F\\x98\\x95", "\\xF0\\x9F\\x91\\x8C", "/*", "look into my eyes 〠.〠", "fkdjsf ksdjfslk", "\\xF0\\x80\\x80\\x80", "aa \\xF0\\x9F\\x98\\x95 aa"}; 
for (int i = 0; i < values.length; i++) { 
    System.out.println(values[i].replaceAll(
        "[\\\\x00-\\\\x7F]|" + //single-byte sequences 0xxxxxxx 
        "[\\\\xC0-\\\\xDF][\\\\x80-\\\\xBF]|" + //double-byte sequences 110xxxxx 10xxxxxx 
        "[\\\\xE0-\\\\xEF][\\\\x80-\\\\xBF]{2}|" + //triple-byte sequences 1110xxxx 10xxxxxx * 2 
        "[\\\\xF0-\\\\xF7][\\\\x80-\\\\xBF]{3}" //quadruple-byte sequence 11110xxx 10xxxxxx * 3 
      , "")); 
} 

o si desea validar si alguna cadena contiene caracteres no utf8 que usaría Pattern.matches como:

String[] values = {"\\xF0\\x9F\\x98\\x95", "\\xF0\\x9F\\x91\\x8C", "/*", "look into my eyes 〠.〠", "fkdjsf ksdjfslk", "\\xF0\\x80\\x80\\x80", "aa \\xF0\\x9F\\x98\\x95 aa"}; 
for (int i = 0; i < values.length; i++) { 
    System.out.println(Pattern.matches(
        ".*(" + 
        "[\\\\x00-\\\\x7F]|" + //single-byte sequences 0xxxxxxx 
        "[\\\\xC0-\\\\xDF][\\\\x80-\\\\xBF]|" + //double-byte sequences 110xxxxx 10xxxxxx 
        "[\\\\xE0-\\\\xEF][\\\\x80-\\\\xBF]{2}|" + //triple-byte sequences 1110xxxx 10xxxxxx * 2 
        "[\\\\xF0-\\\\xF7][\\\\x80-\\\\xBF]{3}" //quadruple-byte sequence 11110xxx 10xxxxxx * 3 
        + ").*" 
      , values[i])); 
} 

Si usted tiene la matriz de bytes disponible que puede filtrar aún más correctamente con:

BufferedReader bufferedReader = null; 
try { 
    bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes), "UTF-8")); 
    for (String currentLine; (currentLine = bufferedReader.readLine()) != null;) { 
     currentLine = currentLine.replaceAll(
         "[\\x00-\\x7F]|" + //single-byte sequences 0xxxxxxx 
         "[\\xC0-\\xDF][\\x80-\\xBF]|" + //double-byte sequences 110xxxxx 10xxxxxx 
         "[\\xE0-\\xEF][\\x80-\\xBF]{2}|" + //triple-byte sequences 1110xxxx 10xxxxxx * 2 
         "[\\xF0-\\xF7][\\x80-\\xBF]{3}" //quadruple-byte sequence 11110xxx 10xxxxxx * 3 
       , "")); 
    } 

para la toma de una aplicación web entera sea compatible con UTF8 leer aquí:
How to get UTF-8 working in Java webapps
More on Byte Encodings and Strings.
Puede verificar su patrón here.
Lo mismo en PHP here.