98 votes

Problème avec les caractères UTF-8 ; ce que je vois n'est pas ce que j'ai stocké

J'ai essayé d'utiliser UTF-8 et j'ai rencontré des problèmes.

J'ai essayé tellement de choses ; voici les résultats que j'ai obtenus :

  • ???? au lieu des caractères asiatiques. Même pour du texte européen, j'ai obtenu Se?or para Señor .
  • Un charabia étrange (Mojibake ?) tel que Señor o para .
  • Les diamants noirs, comme Seor.
  • Finalement, je me suis retrouvé dans une situation où les données ont été perdues, ou du moins tronquées : Se para Señor .
  • Même quand j'ai reçu le texte pour regardez droite, il n'a pas trier correctement.

Qu'est-ce que je fais de mal ? Comment puis-je réparer le code ? Puis-je récupérer le données Si oui, comment ?

171voto

Rick James Points 15994

Ce problème touche les participants de ce site, et bien d'autres.

Vous avez énuméré les cinq principaux cas de CHARACTER SET problèmes.

Meilleure pratique

A l'avenir, il est préférable d'utiliser CHARACTER SET utf8mb4 y COLLATION utf8mb4_unicode_520_ci . (Une version plus récente de la collation Unicode est en préparation).

utf8mb4 est un sur-ensemble de utf8 en ce sens qu'il gère les codes utf8 à 4 octets, qui sont nécessaires pour les Emoji et une partie du chinois.

En dehors de MySQL, "UTF-8" fait référence à tous les codages de taille, et est donc effectivement le même que celui de MySQL. utf8mb4 pas utf8 .

J'essaierai d'utiliser ces orthographes et ces majuscules pour distinguer l'intérieur de MySQL de l'extérieur dans ce qui suit.

Aperçu de ce que vous devrait faire

  • Réglez votre éditeur, etc., sur UTF-8.
  • Les formulaires HTML devraient commencer comme suit <form accept-charset="UTF-8"> .
  • Faites en sorte que vos octets soient codés en UTF-8.
  • Établir UTF-8 comme encodage utilisé dans le client.
  • Avoir la colonne/table déclarée CHARACTER SET utf8mb4 (Vérifiez auprès de SHOW CREATE TABLE .)
  • <meta charset=UTF-8> au début du HTML
  • Les routines stockées acquièrent le jeu de caractères/collation actuel. Elles peuvent avoir besoin d'être reconstruites.

UTF-8 jusqu'au bout

Plus de détails pour les langages informatiques (et ses sections suivantes)

Testez les données

Visualisation des données avec un outil ou avec SELECT ne sont pas dignes de confiance. Trop de clients de ce type, en particulier les navigateurs, essaient de compenser les encodages incorrects et vous montrent le texte correct même si la base de données est tronquée. Choisissez donc une table et une colonne dont le texte n'est pas en anglais et faites ce qui suit

SELECT col, HEX(col) FROM tbl WHERE ...

L'HEX pour un UTF-8 correctement stocké sera

  • Pour un espace vide (dans n'importe quelle langue) : 20
  • Pour l'anglais : 4x , 5x , 6x ou 7x
  • Pour la plupart de l'Europe occidentale, les lettres accentuées doivent être Cxyy
  • Cyrillique, hébreu et farsi/arabe : Dxyy
  • La plupart de l'Asie : Exyyzz
  • Emoji et un peu de chinois : F0yyzzww
  • Plus de détails

Causes et solutions spécifiques des problèmes constatés

Tronqué texte ( Se para Señor ):

  • Les octets à stocker ne sont pas codés en utf8mb4. Corrigez cela.
  • Vérifiez également que la connexion pendant la lecture est UTF-8.

Diamants noirs avec des points d'interrogation ( Seor para Señor ) ; l'un de ces cas existe :

Cas 1 (les octets originaux étaient no UTF-8) :

  • Les octets à stocker ne sont pas encodés en utf8. Corrigez cela.
  • La connexion (ou SET NAMES ) pour le INSERT et le site SELECT n'était pas utf8/utf8mb4. Corrigez cela.
  • Vérifiez également que la colonne dans la base de données est CHARACTER SET utf8 (ou utf8mb4).

Cas 2 (octets originaux) étaient UTF-8) :

  • La connexion (ou SET NAMES ) pour le SELECT n'était pas utf8/utf8mb4. Corrigez cela.
  • Vérifiez également que la colonne dans la base de données est CHARACTER SET utf8 (ou utf8mb4).

Les diamants noirs ne se produisent que lorsque le navigateur est configuré pour <meta charset=UTF-8> .

Points d'interrogation (les normaux, pas les diamants noirs) ( Se?or para Señor ):

  • Les octets à stocker ne sont pas codés en utf8/utf8mb4. Corrigez cela.
  • La colonne dans la base de données n'est pas CHARACTER SET utf8 (ou utf8mb4). Corrigez cela. (Utiliser SHOW CREATE TABLE .)
  • Vérifiez également que la connexion pendant la lecture est UTF-8.

Mojibake ( Señor para Señor ) : (Cette discussion s'applique également à Double encodage qui n'est pas nécessairement visible).

  • Les octets à stocker doivent être encodés en UTF-8. Corrigez cela.
  • La connexion lorsque INSERTing y SELECTing Le texte doit spécifier utf8 ou utf8mb4. Corrigez cela.
  • La colonne doit être déclarée CHARACTER SET utf8 (ou utf8mb4). Corrigez cela.
  • Le code HTML doit commencer par <meta charset=UTF-8> .

Si les données semblent correctes, mais ne sont pas triées correctement, alors soit vous avez choisi la mauvaise collation soit il n'existe pas de collation qui réponde à votre besoin, ou vous avez Double encodage .

Double encodage peut être confirmée en faisant le SELECT .. HEX .. décrite ci-dessus.

é should come back C3A9, but instead shows C383C2A9
The Emoji  should come back F09F91BD, but comes back C3B0C5B8E28098C2BD

C'est-à-dire que l'hexagone est environ deux fois plus long qu'il ne devrait l'être. Ceci est dû à la conversion de latin1 (ou autre) en utf8, puis au traitement de ces octets comme s'ils étaient en latin1. octets comme s'ils étaient en latin1 et en répétant la conversion. Le tri (et la comparaison) ne fonctionne pas correctement car il s'agit, par exemple, de trier comme si la chaîne était Señor .

Corriger les données, si possible

Pour Troncature y Points d'interrogation les données sont perdues.

Pour Mojibake / Double encodage , ...

Pour Diamants noirs , ...

El Corrections sont énumérés ici. (5 solutions différentes pour 5 situations différentes ; choisissez avec soin) : http://mysql.rjweb.org/doc.php/charcoll#fixes_for_various_cases

0 votes

Si le client, la base de données et les tables sont en utf8mb4 Je semble être en mesure de stocker les emojis sans problème. Certains blogs suggèrent également de définir collation-server y character-set-server dans mysqld. Dois-je vraiment changer mysqld quelle différence le paramétrage du serveur fait-il ?

1 votes

@david_adler - Il existe plusieurs façons d'obtenir l'effet de ces paramètres. La meilleure est d'utiliser les paramètres de connexion du client. La deuxième meilleure consiste à exécuter SET NAMES utf8mb4 juste après la connexion. Après tout, il s'agit de déclarer l'encodage dans le fichier client .

0 votes

Avec MySQL 8.0 (maintenant publié), la valeur par défaut est utf8mb4 y utf8mb4_0900_ai_ci . La plupart des utilisateurs devraient les utiliser sans tenir compte des autres jeux de caractères et collations.

11voto

castro_pereira Points 171

J'ai eu des problèmes similaires avec deux de mes projets, après une migration de serveur. Après avoir cherché et essayé de nombreuses solutions, je suis tombé sur celle-ci :

mysqli_set_charset($con,"utf8mb4");

Après avoir ajouté cette ligne à mon fichier de configuration, tout fonctionne bien !

J'ai trouvé cette solution pour MySQLi - _Fonction PHP mysqli set_charset()_ -alors que je cherchais à résoudre une insertion à partir d'une requête HTML.

1 votes

Oui, c'est l'une des nombreuses choses qui peuvent causer des problèmes de jeu de caractères. Remarque : cette syntaxe est valable pour PHP, pas pour les autres langages d'application, et uniquement si vous utilisez la fonction mysqli pas PDO .

0 votes

Vous m'avez sauvé la vie ! Merci (^_^)

2voto

Ashish Bhatt Points 29

J'étais également à la recherche de la même question. Il m'a fallu près d'un mois pour trouver la solution appropriée.

Tout d'abord, vous devrez mettre à jour votre base de données avec tous les CHARACTER et COLLATION récents en utf8mb4 ou au moins qui supportent les données UTF-8.

Pour Java :

lors de l'établissement d'une connexion JDBC, ajoutez ceci à l'URL de connexion useUnicode=yes&characterEncoding=UTF-8 comme paramètres et cela fonctionnera.

Pour Python :

Avant d'effectuer des requêtes dans la base de données, essayez d'appliquer cette règle au curseur.

* cursor.execute('SET NAMES utf8mb4') cursor.execute("SET CHARACTER SET utf8mb4") cursor.execute("SET character_set_connection=utf8mb4") *

Si cela ne fonctionne pas, bonne chasse à la bonne solution.

0 votes

1 mois ? C'était rapide. Il m'a fallu plus d'un an pour formuler ces questions-réponses. Java a l'air bien. SETs ne sont pas la "bonne" méthode pour Python ; voir mysql.rjweb.org/doc.php/charcoll#python De nombreuses autres langues sont abordées ailleurs dans ce blog.

1 votes

@RickJames Mais ce problème existe avec Mysql-Python en dessous de 1.2.4, donc la SET Les déclarations sont essentiellement une solution de contournement.

0 votes

Comment le contenu près de "cursor.execute" est-il censé être formaté ? Des lignes séparées pour chacun d'eux ? Ou autre chose ? Est-ce que "*" est littéral ou destiné à être formaté en italique ?

1voto

SIDU Points 1867
  1. Définissez la langue de votre IDE de code à UTF-8

  2. Ajoutez <meta charset="utf-8"> à l'en-tête de votre page Web où vous recueillez le formulaire de données.

  3. Vérifiez que la définition de votre table MySQL ressemble à ceci :

     CREATE TABLE your_table (
       ...
     ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  4. Si vous utilisez AOP assurez-vous que

    $options = array(PDO::MYSQL_ATTR_INIT_COMMAND=>'SET NAMES utf8');
    $dbL = new PDO($pdo, $user, $pass, $options);

Si vous avez déjà une grande base de données avec le problème ci-dessus, vous pouvez essayer SIDU pour exporter avec le jeu de caractères correct, et réimporter avec UTF-8.

8 votes

(Répondre à sa propre question est une caractéristique de ce forum.) J'ai travaillé pendant des années pour essayer de rendre la réponse aussi concise, mais complète.

0 votes

El DEFAULT CHARSET pour une table n'est que cela, un défaut. Elle peut, et parfois doit, être remplacée par la définition de la colonne.

2 votes

PDO est mieux fait avec l'option charset : $db = new PDO('dblib:host=host;dbname=db;charset=UTF8', $user, $pwd); (Ceci est indiqué dans le lien vers mon document "charcoll").

-4voto

paul Points 2

Selon la configuration du serveur, vous devez modifier l'encodage en conséquence. utf8, d'après ce que vous avez dit, devrait fonctionner le mieux. Cependant, si vous obtenez des caractères bizarres, il pourrait être utile de changer l'encodage de la page Web en ANSI.

Cela m'a aidé lorsque j'ai mis en place un système de gestion de l'information en PHP. MySQLi . Cela pourrait vous aider à mieux comprendre : De ANSI à UTF-8 dans Notepad++.

0 votes

Le bloc-notes ANSI est probablement le plus proche de l'approche MySQL latin1 . Le 0x93 dans ce lien est et proviennent probablement d'un endroit comme Word. Vous pouvez soit convertir en utf8 (hexa E2809C ) ou indiquer à MySQL que les données sont latin1 et espérer que vous ne trébucherez pas ailleurs.

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