2012-02-13 19 views
15

Como MySQL 5.1 no admite secuencias de 4 bytes UTF-8, necesito reemplazar/eliminar las secuencias de 4 bytes en estas cadenas.Cómo reemplazar/eliminar 4 (+) - caracteres de bytes de una cadena UTF-8 en Java?

Estoy buscando una manera limpia de reemplazar estos caracteres.

Las bibliotecas Apache están reemplazando los caracteres con un signo de interrogación está bien para este caso, aunque el equivalente ASCII sería mejor, por supuesto.

N.B. La entrada proviene de fuentes externas (nombres de correo electrónico) y la actualización de la base de datos no es una solución en este momento.

+1

Estás bromeando. MySQL aún no es compatible con Unicode en este día y edad? Eso es desmesurado. Pretender que soporte Unicode cuando solo puede manejar secuencias de UTF-8 de 1, 2 o 3 bytes es una mentira tan grande como decir que admite Unicode cuando solo admite secuencias ASCII de 1 byte. O bien admite cualquier punto de código Unicode legal o no es compatible con Unicode. Es algo binario. Parece que MySQL no es compatible con Unicode. Por favor dime que esto es una broma. – tchrist

+2

@tchrist: MySQL 5.5.3 y superior admiten UTF-8 adecuado a través del nuevo conjunto de caracteres "utf8mb4" "(http://dev.mysql.com/doc/refman/5.5/en/charset-unicode.html) . Sin embargo, el conjunto de caracteres "utf8" solo admite caracteres multibyte UTF-8 de hasta 3 bytes, según los informes para evitar problemas de replicación entre diferentes versiones de MySQL. "utf8" puede cambiar a un alias para "utf8mb4" en una futura versión de MySQL. – ninjalj

+0

Similar a [esta pregunta] (http://stackoverflow.com/questions/8491431/remove-4-byte-characters-from-a-utf-8-string) excepto que está solicitando una solución en PHP en lugar de Java. –

Respuesta

10

Terminamos implementando el siguiente método en Java para este problema. Básicamente reemplazando los caracteres con un punto de código más alto que el último 3 bytes de caracteres UTF-8.

Los cálculos de compensación son para garantizar que permanezcamos en los puntos de código Unicode.

public static final String LAST_3_BYTE_UTF_CHAR = "\uFFFF"; 
public static final String REPLACEMENT_CHAR = "\uFFFD"; 

public static String toValid3ByteUTF8String(String s) { 
    final int length = s.length(); 
    StringBuilder b = new StringBuilder(length); 
    for (int offset = 0; offset < length;) { 
     final int codepoint = s.codePointAt(offset); 

     // do something with the codepoint 
     if (codepoint > CharUtils.LAST_3_BYTE_UTF_CHAR.codePointAt(0)) { 
      b.append(CharUtils.REPLACEMENT_CHAR); 
     } else { 
      if (Character.isValidCodePoint(codepoint)) { 
       b.appendCodePoint(codepoint); 
      } else { 
       b.append(CharUtils.REPLACEMENT_CHAR); 
      } 
     } 
     offset += Character.charCount(codepoint); 
    } 
    return b.toString(); 
} 
+0

Gracias. Lo usé para evitar la conversión de todo mi conjunto de caracteres MySQL. No necesito el personaje alienígena o el personaje Poo en mis datos. – Robert

2

Las secuencias de 5 bytes utf-8 comienzan con un 111110xx-byte y las secuencias de 6 bytes utf-8 comienzan con un 1111110x-byte. Es importante tener en cuenta que no hay bytes de seguimiento de secuencias de 1-4 bytes utf-8 que contengan bytes de gran tamaño porque los bytes de seguimiento siempre tienen el formato 10xxxxxx.

Por lo tanto, puede ir a través de los bytes y cada vez que vea un byte del tipo 111110xx solo emitirá un '?' a la secuencia/matriz de salida omitiendo los siguientes 4 bytes desde la entrada; análogo para las secuencias de 6 bytes.

+2

De todos modos, las secuencias de 5 y 6 bytes no son válidas en UTF-8, eso no significa que no puedan aparecer en el texto fuente. –

+0

sí, lo mejor es estar seguro –

+0

si las secuencias de 5 y 6 bytes no son legales de ninguna manera (deberían) ser menos problemáticas. mi problema es actualmente con secuencias de 4 bytes que son legales pero no compatibles con mysql. – pvgoddijn

4

Otra solución simple es usar la expresión regular [^\u0000-\uFFFF]. Por ejemplo, en java:

text.replaceAll("[^\\u0000-\\uFFFF]", "\uFFFD"); 
+0

Gracias, excelente respuesta – tjeubaoit

Cuestiones relacionadas