2012-02-13 9 views
15

Poiché MySQL 5.1 non supporta sequenze UTF-8 a 4 byte, ho bisogno di sostituire/eliminare le sequenze a 4 byte in queste stringhe.Come sostituire/rimuovere 4 (+) - caratteri di byte da una stringa UTF-8 in Java?

Sto cercando un modo pulito per sostituire questi caratteri.

Le librerie di Apache stanno sostituendo i caratteri con un punto interrogativo che va bene per questo caso, anche se l'equivalente ASCII sarebbe più bello, ovviamente.

N.B. L'input proviene da fonti esterne (nomi e-mail) e l'aggiornamento del database non è una soluzione in questo momento.

+1

Stai scherzando. MySQL non supporta ancora Unicode in questo giorno ed età? È irragionevole. Far finta di supportare Unicode quando si possono gestire solo sequenze UTF-8 a 1, 2 o 3 byte è altrettanto importante affermare che si supporta Unicode quando si supportano solo sequenze ASCII da 1 byte. O supportate qualsiasi punto di codice Unicode legale o non supportate Unicode. È una cosa binaria. Sembra che MySQL non supporti Unicode. Per favore dimmi che questo è uno scherzo. – tchrist

+2

@tchrist: MySQL 5.5.3 e versioni successive supportano l'UTF-8 tramite il nuovo set di caratteri "utf8mb4" (http://dev.mysql.com/doc/refman/5.5/en/charset-unicode.html) . Tuttavia, il set di caratteri "utf8" "supporta solo caratteri multibyte UTF-8 fino a 3 byte, in modo riferito per evitare problemi di replica tra diverse versioni di MySQL. "utf8" potrebbe trasformarsi in un alias per "utf8mb4" in una futura versione di MySQL. – ninjalj

+0

Simile a [questa domanda] (http://stackoverflow.com/questions/8491431/remove-4-byte-characters-from-a-utf-8-string) tranne che richiede una soluzione in PHP anziché in Java. –

risposta

10

Abbiamo finito per implementare il seguente metodo in Java per questo problema. Sostituendo in modo semplice i caratteri con un punto di codice più alto dell'ultimo 3 byte di carattere UTF-8.

I calcoli di offset servono a garantire che restiamo sui punti di codice 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

Grazie. L'ho usato per evitare di convertire il mio intero set di caratteri MySQL. Non ho bisogno del carattere alieno o del carattere cacca nei miei dati. – Robert

2

5 sequenze utf-8 a 5 byte iniziano con un 111110xx byte e 6 byte utf-8 sequenze iniziano con un 1111110-byte. È importante notare che nessun byte di follow-up delle sequenze utf-8 a 1-4 byte contiene byte così grandi perché i byte di follow-up hanno sempre il formato 10xxxxxx.

Quindi è sufficiente passare attraverso i byte e ogni volta che si vede un byte di tipo 111110xx, emettere solo un '?' all'output-stream/array mentre salta i prossimi 4 byte dall'input; analogico per le sequenze a 6 byte.

+2

Le sequenze a 5 e 6 byte non sono comunque valide in UTF-8, ma ciò non significa che non possano apparire nel testo sorgente. –

+0

sì è meglio essere sicuri –

+0

se le sequenze di 5 e 6 byte non sono legali in alcun modo (dovrebbero) essere meno di un problema. il mio problema è attualmente con le sequenze 4byte che sono legali ma supportate da mysql. – pvgoddijn

4

Un'altra soluzione semplice è utilizzare l'espressione regolare [^\u0000-\uFFFF]. Per esempio in Java:

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

Grazie, ottima risposta – tjeubaoit

Problemi correlati