61 votes

Comment corriger les caractères UTF8 doublement encodés (dans une table utf-8)

Un précédent LOAD DATA INFILE a été exécuté en partant du principe que le fichier CSV est latin1 -encodé. Au cours de cette importation, les caractères multi-octets ont été interprétés comme deux caractères uniques, puis encodés en utilisant utf-8 (à nouveau).

Ce double codage a créé des anomalies comme ñ au lieu de ñ .

Comment corriger ces cordes ?

0 votes

@Esailija Ce n'est pas une fonction de MySQL. Il peut être résolu sans avoir recours à des outils comme PHP. (La question a été créée pour être auto-répondue, mais si une meilleure solution est proposée, je l'accepterai à la place de la mienne).

0 votes

C'est bon à savoir. Marquez cette page comme favorite pour que je puisse la trouver quand j'en aurai besoin.

118voto

vbence Points 10528

La fonction MySQL suivante renverra la chaîne utf8 correcte après le double encodage :

CONVERT(CAST(CONVERT(field USING latin1) AS BINARY) USING utf8)

Il peut être utilisé avec un UPDATE pour corriger les champs :

UPDATE tablename SET
    field = CONVERT(CAST(CONVERT(field USING latin1) AS BINARY) USING utf8);

1 votes

J'ai réussi à le faire fonctionner en grande partie, mais j'ai trouvé une séquence qui ne fonctionne pas : lettre e es C49B mais apparaît dans ma base de données comme c384c29b y SELECT HEX(CONVERT(CAST(0xc384c29b AS CHAR) USING latin1)) a obtenu la séquence d'octets UTF-8 invalide C43F ce qui veut dire que votre plus externe CONVERT ne fonctionne pas. Octets UTF-8 c29b doit être unicode 9B mais MySQL le met à 3F ( ? ) probablement parce que c'est un caractère de contrôle en latin1. L'utf8::decode de Perl fonctionne pourtant avec lui.

8 votes

Je ne peux m'empêcher de dire combien je suis heureux d'avoir trouvé cette solution :)

0 votes

Super. Cela semble fonctionner. Maintenant mon défi est de déterminer si seulement un peu de enregistrements ont cette erreur d'encodage, ou tous. Je pourrais avoir besoin de rechercher uniquement les enregistrements comportant des caractères incorrects.

19voto

Eric Points 311

La réponse ci-dessus a fonctionné pour certaines de mes données, mais a donné lieu à un grand nombre de colonnes NULL après l'exécution. Je pense que si la conversion n'a pas été réussie, elle renvoie null. Pour éviter cela, j'ai ajouté une petite vérification.

UPDATE
    tbl

SET
    col =
    CASE
        WHEN CONVERT(CAST(CONVERT(col USING latin1) AS BINARY) USING utf8) IS NULL THEN col
        ELSE CONVERT(CAST(CONVERT(col USING latin1) AS BINARY) USING utf8)
    END

3voto

Stéphane Millien Points 2420

Je rencontre aussi ce problème, voici une solution pour Oracle :

update tablename t set t.colname = convert(t.colname, 'WE8ISO8859P1', 'UTF8') where t.colname like '%Ã%'

Et un autre pour Java :

public static String fixDoubleEncoded(String text) {
    final Pattern pattern = Pattern.compile("^.*Ã[^0-9a-zA-Z\\ \t].*$");
    try {
        while (pattern.matcher(text).matches())
            text = new String(text.getBytes("iso-8859-1"), "utf-8");
    }
    catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return text;
}

3voto

burkul Points 35

Il est très important d'utiliser "utf8mb4" au lieu de "utf8" car mysql supprimera toutes les données après un caractère non reconnu. La méthode la plus sûre est donc la suivante ;

UPDATE tablename SET
field = CONVERT(CAST(CONVERT(field USING latin1) AS BINARY) USING utf8mb4);

Faites attention à ça.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X