J'ai des données sales. Parfois, il contient des caractères comme this . J'utilise ces données pour faire des requêtes comme
WHERE a.address IN ('mydatahere')
Pour ce personnage, je reçois
org.hibernate.exception.GenericJDBCException: mélange illégal de classements (utf8_bin, IMPLICIT), (utf8mb4_general_ci, COERCIBLE), (utf8mb4_general_ci, COERCIBLE) pour l'opération 'IN'
Comment filtrer des personnages comme celui-ci? J'utilise Java.
Merci.
Quand j'ai eu un problème comme celui-ci, j'ai utilisé un script Perl pour m'assurer que les données sont converties en UTF-8 valide en utilisant du code comme celui-ci:
use Encode;
binmode(STDOUT, ":utf8");
while (<>) {
print Encode::decode('UTF-8', $_);
}
Ce script prend (éventuellement corrompu) UTF-8 sur stdin
et réimprime UTF-8 valide dans stdout
. Les caractères non valides sont remplacés par �
(U+FFFD
, caractère de remplacement Unicode ).
Si vous exécutez ce script sur une bonne entrée UTF-8, la sortie doit être identique à l'entrée.
Si vous avez des données dans la base de données, il est judicieux d'utiliser DBI pour analyser vos tables et nettoyer toutes les données en utilisant cette approche pour vous assurer que tout est UTF-8 valide.
Ceci est la version Perl one-liner de ce même script:
Perl -MEncode -e "binmode STDOUT,':utf8';while(<>){print Encode::decode 'UTF-8',\$_}" < bad.txt > good.txt
EDIT: Ajout d'une solution Java uniquement .
Voici un exemple comment faire cela en Java:
import Java.nio.ByteBuffer;
import Java.nio.CharBuffer;
import Java.nio.charset.CharacterCodingException;
import Java.nio.charset.Charset;
import Java.nio.charset.CharsetDecoder;
import Java.nio.charset.CodingErrorAction;
public class UtfFix {
public static void main(String[] args) throws InterruptedException, CharacterCodingException {
CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
decoder.onMalformedInput(CodingErrorAction.REPLACE);
decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
ByteBuffer bb = ByteBuffer.wrap(new byte[] {
(byte) 0xD0, (byte) 0x9F, // 'П'
(byte) 0xD1, (byte) 0x80, // 'р'
(byte) 0xD0, // corrupted UTF-8, was 'и'
(byte) 0xD0, (byte) 0xB2, // 'в'
(byte) 0xD0, (byte) 0xB5, // 'е'
(byte) 0xD1, (byte) 0x82 // 'т'
});
CharBuffer parsed = decoder.decode(bb);
System.out.println(parsed);
// this prints: Пр?вет
}
}
Vous pouvez l'encoder puis le décoder vers/depuis UTF-8:
String label = "look into my eyes 〠.〠";
Charset charset = Charset.forName("UTF-8");
label = charset.decode(charset.encode(label)).toString();
System.out.println(label);
production:
look into my eyes ?.?
edit: Je pense que cela pourrait fonctionner uniquement sur Java 6.
Vous pouvez filtrer les caractères de substitution avec cette expression régulière:
String str = "????"; //U+20000, represented by 2 chars in Java (UTF-16 surrogate pair)
str = str.replaceAll( "([\\ud800-\\udbff\\udc00-\\udfff])", "");
System.out.println(str.length()); //0
Une fois que vous avez converti le tableau d'octets en chaîne sur la machine Java, vous obtiendrez (par défaut sur la plupart des machines) une chaîne codée UTF-16. La bonne solution pour se débarrasser des non UTF-8 caractères est avec le code suivant:
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", "Ok"};
for (int i = 0; i < values.length; i++) {
System.out.println(values[i].replaceAll(
//"[\\\\x00-\\\\x7F]|" + //single-byte sequences 0xxxxxxx - commented because of capitol letters
"[\\\\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
, ""));
}
ou si vous voulez valider si une chaîne contient des caractères non utf8, vous utiliserez Pattern.matches comme:
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", "Ok"};
for (int i = 0; i < values.length; i++) {
System.out.println(Pattern.matches(
".*(" +
//"[\\\\x00-\\\\x7F]|" + //single-byte sequences 0xxxxxxx - commented because of capitol letters
"[\\\\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]));
}
Pour rendre une application Web entière compatible UTF8, lisez ici:
Comment faire fonctionner UTF-8 dans Java webapps
Plus d'informations sur les codages et les chaînes d'octets .
Vous pouvez vérifier votre modèle ici .
La même chose dans PHP ici .
In PHP - J'approche cela en n'autorisant que les données imprimables. Cela aide vraiment à nettoyer les données pour la base de données.
C'est du prétraitement et parfois, vous n'avez pas ce luxe.
$str = preg_replace('/[[:^print:]]/', '', $str);