Intermédiaire 8 min de lecture 25 janvier 2025

Python Unicode : encodage, caractères et pièges à éviter

En Python 3, les chaînes str sont Unicode et les bytes représentent des octets. Les soucis arrivent quand on mélange les deux, qu’un fichier n’est pas en UTF‑8, ou qu’un caractère invisible se glisse dans une chaîne. Voici comment penser Unicode en Python pour éviter erreurs, comparaisons fausses et imports capricieux.

Comprendre Unicode en Python

Python 3 manipule des chaînes Unicode. Les erreurs classiques viennent d’encodages incohérents, de conversions implicites ou de caractères spéciaux invisibles.

Les notions essentielles à maîtriser en Python Unicode :

1 Chaînes Python : str et bytes

Différence de nature et conversions explicites.

str = texte Unicode, bytes = suite d’octets, bytearray = mutable

2 Encodages et conversions

Choix d’encodage et conversions encode()/decode().

UTF‑8 (recommandé), UTF‑16 (BOM), Latin‑1/CP1252 (héritage)

3 Espaces et séparateurs Unicode fréquents

Souvent sources de bugs en comparaisons et découpages.

NBSP (U+00A0) - Espace insécable
ZWSP (U+200B) - Zero Width Space
ZWNBSP (U+FEFF) - Zero Width No-Break Space
Thin Space (U+2009), Hair Space (U+200A)

4 Marques techniques et direction du texte

BOM, soft hyphen et contrôles bidirectionnels impactent la logique.

BOM (U+FEFF) - Byte Order Mark
Soft Hyphen (U+00AD) - Tiret conditionnel
LRM, RLM, LRE, RLE - Contrôles Bidi

Problèmes classiques

Mélange str/bytes

Concaténer du texte et des octets lève des erreurs ou masque un encodage implicite.

UnicodeDecodeError / UnicodeEncodeError

Un fichier non‑UTF‑8 ou un terminal mal configuré provoquent des erreurs de conversion.

strip() ou split() surprises

Certains séparateurs zéro largeur ou marques spéciales perturbent le nettoyage et la découpe.

Regex \s et classes de caractères

En Python, \s est Unicode mais n’englobe pas tout (ex. ZWSP, marques Bidi).

Exemple de problème courant :

# Deux emails qui paraissent identiques
s1 = "email@domaine.com"
s2 = "email@domaine.com\u200b" # ZWSP à la fin
assert s1 == s2 # ❌ Échec (AssertionError)

Symptômes qui doivent vous alerter

🚨 Signaux d'alarme

!
Un diff git montre des changements incompréhensibles dans des fichiers Python
!
pandas.read_csv() n’obtient pas le bon nombre de colonnes
!
python-dotenv ne charge pas une clé alors que la ligne paraît correcte
!
Le curseur saute sur un carré invisible dans l’éditeur de code
!
Un copier‑coller dans le REPL/terminal déclenche une erreur de commande

Comment les détecter

Solution recommandée : Clean ASCII

Clean ASCII met en évidence les caractères non‑ASCII et invisibles que vos scripts Python peinent à afficher. Visualisez les points de code exacts et corrigez facilement avant de lire/écrire vos fichiers.

✅ Détection automatique

NBSP, ZWSP, BOM, soft hyphens, caractères de contrôle

📊 Analyse complète

Points de code Unicode, positions, normalisation conseillée

🧹 Nettoyage automatique

Remplacements sûrs vers ASCII ou standard Unicode

💾 Export propre

Téléchargement prêt à traiter avec open(..., encoding="utf-8")

Autres méthodes de détection

Affichage dans l'éditeur

Activez "render whitespace" et la visualisation des caractères spéciaux
Utilisez un linter qui signale NBSP/ZWSP dans les sources Python

En ligne de commande (Unix)

# Localiser des octets hors ASCII imprimable
grep -P "[^\x09\x0A\x0D\x20-\x7E]" fichier.txt
# Visualiser fins de ligne et tabulations
sed -n l fichier.txt
# Afficher les caractères de contrôle
cat -A fichier.txt
# Inspecter les codes hexadécimaux
hexdump -C fichier.txt

En code

Python (points de code)

[f"U+{ord(c):04X}" for c in s]

Python (hors ASCII imprimable)

[c for c in s if ord(c) < 32 or ord(c) > 126]

Excel / Google Sheets (données issues de Python)

CODE(MID(cellule;position;1))

Nettoyer et prévenir

🚀 Solution rapide avec Clean ASCII

Avant d’écrire du code de sanitation, passez vos textes par Clean ASCII pour traquer les intrus fréquents que Python affichera mal.

Détection automatique
Nettoyage intelligent
Export immédiat

Méthodes techniques avancées

🔧 Normaliser

Utilisez unicodedata.normalize('NFC' ou 'NFKC') pour uniformiser les chaînes
Supprimez les BOM inutiles dans les fichiers UTF‑8
Uniformisez les fins de ligne (dos2unix, .gitattributes)

🧹 Filtrer

Écrivez une fonction clean_unicode() pour enlever séparateurs zéro largeur et contrôles
Remplacez NBSP par espace standard si nécessaire
Bloquez les caractères de contrôle hors LF/CR/HT

⚙️ Automatiser

Hooks pre-commit pour refuser des fichiers contenant des points de code indésirables
Tests de sanitation sur les entrées utilisateurs et les pipelines ETL Python
Linting sur la CI pour détecter des caractères hors plage

Checklist rapide

Fichiers lus/écrits en UTF‑8 via open(..., encoding="utf-8") sans BOM
Fins de ligne uniformes via gitattributes
Éditeur configuré pour afficher les espaces et caractères invisibles
Fonctions Python de nettoyage Unicode dans vos utilitaires
Tests vérifiant l’absence de caractères de contrôle indésirables
Documentation interne sur encodages, normalisation et EOL

Conclusion

Maîtriser Unicode en Python, c’est éviter des heures de debug sur des soucis d’encodage, de parsing ou de comparaisons faussement identiques.

Adoptez UTF‑8 partout, normalisez vos chaînes, détectez les caractères invisibles et automatisez les contrôles : vous rendrez vos applications Python robustes face au texte du monde réel.

Détectez les caractères invisibles maintenant

Utilisez notre outil pour identifier et nettoyer les caractères problématiques avant leur traitement en Python.

Analyser mon texte