utf8 example convertir convert bytes java string unicode encoding

convertir - encoding utf-8 java example



Cómo determinar si una cadena contiene caracteres codificados no válidos (10)

Debe configurar la codificación de caracteres desde el principio. Intente enviar el encabezado Content-Type adecuado, por ejemplo Content-Type: text / html; charset = utf-8 para corregir la codificación correcta. La conformidad estándar se refiere a utf-8 y utf-16 como la codificación adecuada para los servicios web. Examina tus encabezados de respuesta.

Además, en el lado del servidor, en el caso de que el navegador no maneje adecuadamente la codificación enviada por el servidor, fuerce la codificación asignando un nuevo String. También puede verificar cada byte en la cadena codificada utf-8 haciendo un único each_byte y 0x80 , verificando el resultado como distinto de cero.

boolean utfEncoded = true; byte[] strBytes = queryString.getBytes(); for (int i = 0; i < strBytes.length(); i++) { if ((strBytes[i] & 0x80) != 0) { continue; } else { /* treat the string as non utf encoded */ utfEncoded = false; break; } } String realQueryString = utfEncoded ? queryString : new String(queryString.getBytes(), "iso-8859-1");

Además, eche un vistazo a este artículo , espero que lo ayude.

Escenario de uso

Hemos implementado un servicio web que nuestros desarrolladores de frontend web usan (a través de una API) internamente para mostrar los datos del producto. En el sitio web, el usuario ingresa algo (es decir, una cadena de consulta). Internamente, el sitio web realiza una llamada al servicio a través de la API.

Nota: usamos restlet, no tomcat

Problema original

Firefox 3.0.10 parece respetar la codificación seleccionada en el navegador y codificar una URL según la codificación seleccionada. Esto da como resultado diferentes cadenas de consulta para ISO-8859-1 y UTF-8.

Nuestro sitio web reenvía la información del usuario y no la convierte (lo que debería hacer), por lo que puede hacer una llamada al servicio a través de la API llamando a un servicio web utilizando una cadena de consulta que contiene diéresis alemanas.

Es decir, para una pieza de consulta que se parece a

...v=abcädef

si se selecciona "ISO-8859-1", la parte de consulta enviada se ve como

...v=abc%E4def

pero si se selecciona "UTF-8", la parte de consulta enviada se ve como

...v=abc%C3%A4def

Solución deseada

Como controlamos el servicio, porque lo hemos implementado, queremos verificar en el lado del servidor si la llamada contiene caracteres que no sean utf-8, de ser así, responda con un estado http 4xx

Solución actual en detalle

Compruebe para cada carácter (== string.substring (i, i + 1))

  1. si character.getBytes () [0] es igual a 63 para ''?''
  2. si Character.getType (character.charAt (0)) devuelve OTHER_SYMBOL

Código

protected List< String > getNonUnicodeCharacters( String s ) { final List< String > result = new ArrayList< String >(); for ( int i = 0 , n = s.length() ; i < n ; i++ ) { final String character = s.substring( i , i + 1 ); final boolean isOtherSymbol = ( int ) Character.OTHER_SYMBOL == Character.getType( character.charAt( 0 ) ); final boolean isNonUnicode = isOtherSymbol && character.getBytes()[ 0 ] == ( byte ) 63; if ( isNonUnicode ) result.add( character ); } return result; }

Pregunta

¿Capturará esto todos los caracteres no válidos (no codificados en utf)? ¿Alguno de ustedes tiene una solución mejor (más fácil)?

Nota: Comprobé URLDecoder con el siguiente código

final String[] test = new String[]{ "v=abc%E4def", "v=abc%C3%A4def" }; for ( int i = 0 , n = test.length ; i < n ; i++ ) { System.out.println( java.net.URLDecoder.decode(test[i],"UTF-8") ); System.out.println( java.net.URLDecoder.decode(test[i],"ISO-8859-1") ); }

Esto imprime:

v=abc?def v=abcädef v=abcädef v=abcädef

y no arroja un suspiro de IllegalArgumentException


Es posible que desee incluir un parámetro conocido en sus solicitudes, por ejemplo, "... & encTest = ä €", para diferenciar de forma segura entre las diferentes codificaciones.


Esto es lo que usé para verificar la codificación:

CharsetDecoder ebcdicDecoder = Charset.forName("IBM1047").newDecoder(); ebcdicDecoder.onMalformedInput(CodingErrorAction.REPORT); ebcdicDecoder.onUnmappableCharacter(CodingErrorAction.REPORT); CharBuffer out = CharBuffer.wrap(new char[3200]); CoderResult result = ebcdicDecoder.decode(ByteBuffer.wrap(bytes), out, true); if (result.isError() || result.isOverflow() || result.isUnderflow() || result.isMalformed() || result.isUnmappable()) { System.out.println("Cannot decode EBCDIC"); } else { CoderResult result = ebcdicDecoder.flush(out); if (result.isOverflow()) System.out.println("Cannot decode EBCDIC"); if (result.isUnderflow()) System.out.println("Ebcdic decoded succefully "); }

Editar: actualizado con la sugerencia de Vouze


He estado trabajando en un problema similar de "adivinar la codificación". La mejor solución implica conocer la codificación. Salvo eso, puede hacer conjeturas para distinguir entre UTF-8 e ISO-8859-1.

Para responder a la pregunta general de cómo detectar si una cadena está codificada correctamente UTF-8, puede verificar lo siguiente:

  1. Ningún byte es 0x00, 0xC0, 0xC1, o en el rango 0xF5-0xFF.
  2. Los bytes de cola (0x80-0xBF) siempre van precedidos de un byte de cabeza 0xC2-0xF4 u otro byte de cola.
  3. Los bytes principales deben predecir correctamente el número de bytes de cola (por ejemplo, cualquier byte en 0xC2-0xDF debe ir seguido de exactamente un byte en el rango 0x80-0xBF).

Si una cadena pasa todas esas pruebas, entonces es interpretable como UTF-8 válido. Eso no garantiza que sea UTF-8, pero es un buen predictor.

La entrada legal en ISO-8859-1 probablemente no tendrá caracteres de control (0x00-0x1F y 0x80-0x9F) distintos de los separadores de línea. Parece que 0x7F tampoco está definido en ISO-8859-1.

(Estoy basando esto fuera de las páginas de Wikipedia para UTF-8 e ISO-8859-1.)


Intente usar UTF-8 como predeterminado, como siempre en cualquier lugar donde pueda tocar. (Base de datos, memoria y UI)

La codificación de un solo y único juego de caracteres podría reducir una gran cantidad de problemas, y en realidad puede acelerar el rendimiento de su servidor web. Hay tanta potencia de procesamiento y memoria desperdiciada para codificar / decodificar.


Puede usar un CharsetDecoder configurado para lanzar una excepción si se encuentran caracteres no válidos:

CharsetDecoder UTF8Decoder = Charset.forName("UTF8").newDecoder().onMalformedInput(CodingErrorAction.REPORT);

Ver CodingErrorAction.REPORT


Reemplazar todos los caracteres de control en una cadena vacía

value = value.replaceAll("//p{Cntrl}", "");


Yo hice la misma pregunta,

Manejo de la codificación de caracteres en URI en Tomcat

Recientemente encontré una solución y funciona bastante bien para mí. Es posible que desee intentarlo. Aquí está lo que tú necesitas hacer,

  1. Deje su codificación URI como Latin-1. En Tomcat, agregue URIEncoding = "ISO-8859-1" al conector en server.xml.
  2. Si tiene que decodificar URL manualmente, use Latin1 como charset también.
  3. Use la función fixEncoding () para corregir codificaciones.

Por ejemplo, para obtener un parámetro de una cadena de consulta,

String name = fixEncoding(request.getParameter("name"));

Puedes hacer esto siempre La cadena con la codificación correcta no se cambia.

El código está adjunto. ¡Buena suerte!

public static String fixEncoding(String latin1) { try { byte[] bytes = latin1.getBytes("ISO-8859-1"); if (!validUTF8(bytes)) return latin1; return new String(bytes, "UTF-8"); } catch (UnsupportedEncodingException e) { // Impossible, throw unchecked throw new IllegalStateException("No Latin1 or UTF-8: " + e.getMessage()); } } public static boolean validUTF8(byte[] input) { int i = 0; // Check for BOM if (input.length >= 3 && (input[0] & 0xFF) == 0xEF && (input[1] & 0xFF) == 0xBB & (input[2] & 0xFF) == 0xBF) { i = 3; } int end; for (int j = input.length; i < j; ++i) { int octet = input[i]; if ((octet & 0x80) == 0) { continue; // ASCII } // Check for UTF-8 leading byte if ((octet & 0xE0) == 0xC0) { end = i + 1; } else if ((octet & 0xF0) == 0xE0) { end = i + 2; } else if ((octet & 0xF8) == 0xF0) { end = i + 3; } else { // Java only supports BMP so 3 is max return false; } while (i < end) { i++; octet = input[i]; if ((octet & 0xC0) != 0x80) { // Not a valid trailing byte return false; } } } return true; }

EDITAR: su enfoque no funciona por varias razones. Cuando hay errores de codificación, no puede contar con lo que obtiene de Tomcat. A veces obtienes o? Otras veces, no obtendría nada, getParameter () devuelve null. Supongamos que puede verificar "?", ¿Qué ocurre con que su cadena de consulta contiene "?" Válido. ?

Además, no debes rechazar ninguna solicitud. Esto no es culpa de tu usuario. Como mencioné en mi pregunta original, el navegador puede codificar URL en UTF-8 o Latin-1. El usuario no tiene control. Tienes que aceptar ambos. Cambiar su servlet a Latin-1 conservará todos los caracteres, incluso si son incorrectos, para darnos la posibilidad de arreglarlo o tirarlo.

La solución que publiqué aquí no es perfecta, pero es la mejor que encontramos hasta ahora.


la siguiente expresión regular puede ser de su interés:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/185624

Lo uso en ruby ​​de la siguiente manera:

module Encoding UTF8RGX = //A( [/x09/x0A/x0D/x20-/x7E] # ASCII | [/xC2-/xDF][/x80-/xBF] # non-overlong 2-byte | /xE0[/xA0-/xBF][/x80-/xBF] # excluding overlongs | [/xE1-/xEC/xEE/xEF][/x80-/xBF]{2} # straight 3-byte | /xED[/x80-/x9F][/x80-/xBF] # excluding surrogates | /xF0[/x90-/xBF][/x80-/xBF]{2} # planes 1-3 | [/xF1-/xF3][/x80-/xBF]{3} # planes 4-15 | /xF4[/x80-/x8F][/x80-/xBF]{2} # plane 16 )*/z/x unless defined? UTF8RGX def self.utf8_file?(fileName) count = 0 File.open("#{fileName}").each do |l| count += 1 unless utf8_string?(l) puts count.to_s + ": " + l end end return true end def self.utf8_string?(a_string) UTF8RGX === a_string end end


URLDecoder decodificará a una codificación dada. Esto debería marcar los errores apropiadamente. Sin embargo, la documentación dice:

Hay dos formas posibles en que este decodificador podría manejar cadenas ilegales. Podría dejar personajes ilegales solo o podría lanzar una IllegalArgumentException. Qué enfoque toma el decodificador se deja a la implementación.

Entonces probablemente deberías probarlo. Tenga en cuenta también (de la documentación del método decode ()):

La Recomendación del World Wide Web Consortium establece que se debe usar UTF-8. No hacerlo puede introducir incompatibilidades

¡entonces hay algo más en qué pensar!

EDITAR: Apache Commons URLDecode afirma arrojar excepciones apropiadas para codificaciones incorrectas.