Intermédiaire 8 min de lecture 25 janvier 2025

utf8mb4, Unicode et utf8mb4_unicode_ci: comprendre et éviter les pièges

Tri incohérent, questions d’accents, emoji tronqués, comparaisons qui varient entre votre machine et la CI. La plupart de ces surprises viennent d’un mélange d’encodage UTF‑8, de collation MySQL et de normalisation Unicode. Voici comment aborder utf8mb4, la collation utf8mb4_unicode_ci et garder des résultats stables partout.

Qu'est-ce que utf8mb4 et la collation utf8mb4_unicode_ci ?

utf8mb4 est l’UTF‑8 complet côté MySQL (jusqu’à 4 octets), et utf8mb4_unicode_ci est une collation Unicode offrant des comparaisons et tris insensibles à la casse conformes aux règles Unicode.

Voici les blocs fondamentaux à connaître :

1 Jeux de caractères côté MySQL

Capacité et portée des encodages courants :

utf8mb4 (4 octets), utf8 (3), latin1 (1), ascii (1)

2 Collations utf8mb4

Règles de comparaison et de tri :

utf8mb4_general_ci, utf8mb4_unicode_ci, utf8mb4_0900_ai_ci, utf8mb4_bin

3 Suffixes et comportements (_ci, _cs, _ai, _as)

Impacts sur l’égalité et l’ordonnancement :

_ci = case insensitive
_cs = case sensitive
_ai = accent insensitive
_as = accent sensitive

4 Spécificités Unicode

Éléments à ne pas ignorer :

Emoji et symboles (plan multilingue complémentaire)
Caractères composés vs décomposés (NFC/NFD)
Équivalences Unicode et règles de pliage de casse

Problèmes classiques

Bases créées en utf8 (3 octets) au lieu de utf8mb4

Emoji tronqués, points d’interrogation, erreurs 1366/1406 lors des insertions.

Tri et LIKE différents entre machines

_general_ci vs _unicode_ci vs _0900_ai_ci changent l’ordre et les correspondances.

Comparaisons applicatives vs SQL incohérentes

Chaînes équivalentes en base (utf8mb4_unicode_ci) mais différentes octet à octet côté code.

CI qui passe/échoue selon l’image MySQL

Variables serveur (character_set_server, collation_server) différentes dans la CI.

Exemple de cas réel :

# Deux chaînes visuellement identiques mais codées différemment
string1 = "école" # U+00E9 (NFC)
string2 = "école" # U+0065 + U+0301 (NFD)
assert string1 == string2 # ❌ Échec côté code sans normalisation
-- ✅ Égalité en SQL avec collation Unicode insensible aux accents
SELECT "école" = "école" COLLATE utf8mb4_unicode_ci; -- renvoie 1

Symptômes qui doivent vous alerter

🚨 Signaux d'alarme

!
Classement/ORDER BY différents entre local et CI/CD
!
Emoji remplacés par ? ou erreurs lors d’inserts en production
!
LIKE et comparaisons insensibles à la casse qui ne réagissent pas pareil
!
Contraintes UNIQUE acceptées/refusées différemment selon l’environnement
!
Comparaisons côté code qui ne collent pas aux résultats SQL

Comment les détecter

Solution recommandée : Clean ASCII

Clean ASCII aide à vérifier la validité UTF‑8, repérer les octets hors plage et visualiser les points de code. Vous voyez immédiatement les caractères non standard et pouvez normaliser vos chaînes avant import en utf8mb4_unicode_ci.

✅ Validation UTF‑8

Détecte octets invalides, séquences tronquées, paires non conformes

📊 Analyse Unicode

Code points, formes composées/décomposées, différences visibles

🧹 Normalisation

Suggestions NFC/NFKC pour stabiliser comparaisons et tris

💾 Export compatible

Texte prêt pour MySQL/MariaDB en utf8mb4

Autres méthodes de détection

Affichage dans l'éditeur

“Reopen with Encoding: UTF‑8”, “render whitespace/control characters” dans VS Code/JetBrains/Sublime
Linter pour surligner octets non UTF‑8 et mélanges d’encodages

En ligne de commande (Unix)

# Paramètres MySQL liés à l'encodage et la collation
mysql -e "SHOW VARIABLES LIKE 'character_set%'; SHOW VARIABLES LIKE 'collation%';"
# Vérifier l'encodage d'un dump
file -bi dump.sql
iconv -f UTF-8 -t UTF-8 -o /dev/null dump.sql || echo "Octets UTF-8 invalides"
# Afficher les caractères et octets
hexdump -C échantillon.txt
# Export avec utf8mb4
mysqldump --default-character-set=utf8mb4 --skip-set-charset base > dump.sql

En code

JavaScript

Array.from(str.normalize('NFC')).map(c => c.codePointAt(0).toString(16))

Python

import unicodedata; s = unicodedata.normalize("NFC", s)

Excel / Google Sheets

UNICODE(MID(cellule;position;1))

Nettoyer et prévenir

🚀 Solution rapide avec Clean ASCII

Avant d’écrire des migrations, passez vos textes dans Clean ASCII : validation UTF‑8, visualisation des points de code et normalisation pour préparer un import en utf8mb4_unicode_ci.

Détection d’octets invalides
Normalisation NFC/NFKC
Export prêt pour MySQL

Méthodes techniques avancées

🔧 Normaliser

Adoptez UTF‑8 partout et forcez utf8mb4 côté serveur, base, tables, colonnes
Choisissez une collation unique (utf8mb4_unicode_ci ou utf8mb4_0900_ai_ci selon version)
Normalisez les chaînes en NFC avant stockage et comparaison

🧹 Filtrer

Rejetez ou remappez tout octet non UTF‑8 avant insertion
Harmonisez les espaces et tirets typographiques si la recherche doit les ignorer
Alignez LOWER/UPPER et pliage de casse avec la collation choisie

⚙️ Automatiser

Scripts CI vérifiant character_set_server et collation_server attendus
Pre-commit qui refuse des DDL/Dumps en CHARSET=utf8 (sans mb4)
Tests end-to-end validant tri, LIKE et unicité sur données accentuées/emoji

Checklist rapide

Serveur, base, tables et colonnes en utf8mb4
Collation choisie et documentée (utf8mb4_unicode_ci ou 0900_ai_ci)
Connexion applicative SET NAMES utf8mb4 / charset utf8mb4
Normalisation NFC côté application avant comparaison
Dump/restore avec --default-character-set=utf8mb4
CI qui vérifie les variables d’encodage/collation et exécute des tests sur données Unicode

Conclusion

Alignez votre encodage sur utf8mb4, choisissez une collation Unicode cohérente et normalisez vos chaînes pour éviter les surprises.

En synchronisant application, base et CI autour d’utf8mb4_unicode_ci, vous stabilisez tris, comparaisons et unicité, y compris avec les emojis.

Vérifiez vos chaînes et dumps maintenant

Utilisez notre outil pour valider UTF‑8, visualiser Unicode et préparer des données propres pour utf8mb4_unicode_ci.

Analyser mon texte