La clé de ces problèmes d'encodage est de comprendre qu'il existe en principe Deux concepts distincts de "chaîne". : (1) chaîne de caractères et (2) chaîne/réseau de octets . Cette distinction a longtemps été ignorée en raison de l'omniprésence historique des codages ne comportant pas plus de 256 caractères (ASCII, Latin-1, Windows-1252, Mac OS Roman, ) : ces codages font correspondre un ensemble de caractères communs à des nombres compris entre 0 et 255 (c'est-à-dire des octets) ; l'échange relativement limité de fichiers avant l'avènement du web rendait cette situation d'encodages incompatibles tolérable, car la plupart des programmes pouvaient ignorer le fait qu'il y avait plusieurs encodages tant qu'ils produisaient du texte qui restait sur le même système d'exploitation : ces programmes traitaient simplement le texte comme des octets (à travers l'encodage utilisé par le système d'exploitation). La vision correcte et moderne sépare correctement ces deux concepts de chaîne de caractères, en se basant sur les deux points suivants :
-
Personnages sont pour la plupart sans rapport avec les ordinateurs Les "caractères" pour les machines comprennent également les "instructions de dessin", comme par exemple les espaces, le retour chariot, les instructions pour définir le sens de l'écriture (pour l'arabe, etc.), les accents, etc. A très grande liste de caractères est inclus dans le Unicode standard ; il couvre la plupart des caractères connus.
-
D'autre part, les ordinateurs ont besoin de représenter les caractères abstraits d'une manière ou d'une autre : pour cela, ils utilisent tableaux d'octets (chiffres compris entre 0 et 255 inclus), car leur mémoire se présente sous forme de blocs d'octets. Le processus nécessaire pour convertir les caractères en octets est appelé codage . Ainsi, un ordinateur nécessite un codage afin de représenter les caractères. Tout texte présent sur votre ordinateur est codé (jusqu'à ce qu'il soit affiché), qu'il soit envoyé à un terminal (qui attend des caractères codés d'une manière spécifique), ou enregistré dans un fichier. Afin d'être affichés ou correctement "compris" (par l'interpréteur Python, par exemple), les flux d'octets sont décodé en caractères. Quelques encodages (UTF-8, UTF-16, ) sont définis par Unicode pour sa liste de caractères (Unicode définit donc à la fois une liste de caractères et des codages pour ces caractères - il y a encore des endroits où l'on voit l'expression "codage Unicode" comme un moyen de se référer à l'omniprésent UTF-8, mais c'est une terminologie incorrecte, car Unicode fournit multiple codages).
En résumé, les ordinateurs doivent représenter en interne les caractères avec des octets et ils le font par le biais de deux opérations :
Encodage : caractères octets
Décodage : octets caractères
Certains codages ne peuvent pas coder tous les caractères (par exemple, ASCII), tandis que (certains) codages Unicode vous permettent de coder tous les caractères Unicode. L'encodage n'est pas non plus nécessairement unique car certains caractères peuvent être représentés soit directement, soit sous la forme d'une combinaison de caractères. combinaison (par exemple, d'un caractère de base et d'accents).
Notez que le concept de nouvelle ligne ajoute une couche de complication puisqu'il peut être représenté par différents caractères (de contrôle) qui dépendent du système d'exploitation (c'est la raison pour laquelle Python est doté de l'option mode de lecture universel des fichiers de nouvelles lignes ).
Quelques informations supplémentaires sur Unicode, les caractères et les points de code, si vous êtes intéressé :
Maintenant, ce que j'ai appelé "caractère" ci-dessus est ce qu'Unicode appelle un " caractère perçu par l'utilisateur ". Un seul caractère perçu par l'utilisateur peut parfois être représenté dans Unicode en combinant des parties de caractères (caractère de base, accents, ) se trouvant à différents endroits de la chaîne de production. indices dans la liste Unicode, qui sont appelés " points de code " - ces points de code peuvent être combinés ensemble pour former un " cluster de graphèmes ". Unicode conduit donc à un troisième concept de chaîne, constitué d'une séquence de points de code Unicode, qui se situe entre les chaînes d'octets et les chaînes de caractères, et qui se rapproche de ces dernières. Je les appellerai " Chaînes de caractères Unicode " (comme dans Python 2).
Alors que Python peut imprimer des chaînes de caractères (perçues par l'utilisateur), Les chaînes de caractères non octets de Python sont essentiellement des séquences de points de code Unicode. et non des caractères perçus par l'utilisateur. Les valeurs des points de code sont celles utilisées dans le langage Python. \u
et \U
Syntaxe des chaînes de caractères Unicode. Ils ne doivent pas être confondus avec l'encodage d'un caractère (et ne doivent pas avoir de relation avec celui-ci : Les points de code Unicode peuvent être encodés de diverses manières).
Cela a une conséquence importante : la longueur d'une chaîne de caractères Python (Unicode) est son nombre de points de code, soit pas toujours son nombre de caractères perçus par l'utilisateur : donc s = "\u1100\u1161\u11a8"; print(s, "len", len(s))
(Python 3) donne len 3
malgré s
avoir un seul caractère perçu par l'utilisateur (coréen) (parce qu'il est représenté par 3 points de code - même s'il n'est pas nécessaire, comme le montre l'exemple ci-dessous). print("\uac01")
spectacles). Toutefois, dans de nombreuses circonstances pratiques, la longueur d'une chaîne de caractères correspond au nombre de caractères perçus par l'utilisateur, car de nombreux caractères sont généralement stockés par Python sous la forme d'un seul point de code Unicode.
Sur Python 2 les chaînes Unicode sont appelées "chaînes Unicode" ( unicode
type, forme littérale u"…"
), tandis que les tableaux d'octets sont des "chaînes" ( str
où le tableau d'octets peut par exemple être construit avec des chaînes de caractères. "…"
). Sur le site Python 3 Les chaînes de caractères Unicode sont simplement appelées "chaînes de caractères" ( str
type, forme littérale "…"
), alors que les tableaux d'octets sont des "octets" ( bytes
type, forme littérale b"…"
). En conséquence, quelque chose comme ""[0]
donne un résultat différent dans Python 2 ( '\xf0'
un octet) et Python 3 ( ""
le premier et unique caractère).
Avec ces quelques points clés, vous devriez être en mesure de comprendre la plupart des questions relatives à l'encodage !
Normalement, lorsque vous imprimer u"…"
à un terminal vous ne devriez pas obtenir de déchets : Python connaît l'encodage de votre terminal. En fait, vous pouvez vérifier quel est l'encodage attendu par le terminal :
% python
Python 2.7.6 (default, Nov 15 2013, 15:20:37)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print sys.stdout.encoding
UTF-8
Si vos caractères d'entrée peuvent être encodés avec l'encodage du terminal, Python le fera et enverra les octets correspondants à votre terminal sans se plaindre. Le terminal fera alors de son mieux pour afficher les caractères après avoir décodé les octets d'entrée (dans le pire des cas, la police du terminal ne possède pas certains des caractères et imprimera une sorte de blanc à la place).
Si vos caractères d'entrée ne peuvent pas être encodés avec l'encodage du terminal, cela signifie que le terminal n'est pas configuré pour afficher ces caractères. Python se plaindra (en Python avec une icône UnicodeEncodeError
puisque la chaîne de caractères ne peut pas être codée d'une manière adaptée à votre terminal). La seule solution possible est d'utiliser un terminal qui peut afficher les caractères (soit en configurant le terminal de façon à ce qu'il accepte un codage qui puisse représenter vos caractères, soit en utilisant un autre programme de terminal). Ceci est important lorsque vous distribuez des programmes qui peuvent être utilisés dans différents environnements : les messages que vous imprimez doivent pouvoir être représentés dans le terminal de l'utilisateur. Il est donc parfois préférable de s'en tenir à des chaînes de caractères qui ne contiennent que des caractères ASCII.
Cependant, lorsque vous redirige ou pipe la sortie de votre programme, il n'est généralement pas possible de savoir quel est l'encodage d'entrée du programme récepteur, et le code ci-dessus renvoie un encodage par défaut : Aucun (Python 2.7) ou UTF-8 (Python 3) :
% python2.7 -c "import sys; print sys.stdout.encoding" | cat
None
% python3.4 -c "import sys; print(sys.stdout.encoding)" | cat
UTF-8
L'encodage de stdin, stdout et stderr peut cependant être set à travers le PYTHONIOENCODING
la variable d'environnement, si nécessaire :
% PYTHONIOENCODING=UTF-8 python2.7 -c "import sys; print sys.stdout.encoding" | cat
UTF-8
Si l'impression vers un terminal ne produit pas ce que vous attendez, vous pouvez vérifier que le codage UTF-8 que vous avez introduit manuellement est correct ; par exemple, votre premier caractère ( \u001A
) n'est pas imprimable, si je ne me trompe pas .
Sur http://wiki.python.org/moin/PrintFails vous pouvez trouver une solution comme la suivante, pour Python 2.x :
import codecs
import locale
import sys
# Wrap sys.stdout into a StreamWriter to allow writing unicode.
sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)
uni = u"\u001A\u0BC3\u1451\U0001D10C"
print uni
Pour Python 3, vous pouvez vérifier une des questions posées précédemment sur StackOverflow.
0 votes
Ce site pourrait également vous aider.
0 votes
Lorsque j'essaie de reproduire votre constat, j'obtiens une UnicodeEncodeError, et non une UnicodeDecodeError. gist.github.com/jaraco/12abfc05872c65a4f3f6cd58b6f9be4d