137 votes

Pourquoi Python imprime des caractères unicode lorsque l’encodage par défaut est ASCII ?

À partir de la version 2.6 de Python shell:

>>> import sys
>>> print sys.getdefaultencoding()
ascii
>>> print u'\xe9'
é
>>> 

J'ai attendu d'avoir un charabia ou un message d'Erreur après l'instruction print, depuis le "é" de caractère ne fait pas partie de l'ASCII et je n'ai pas spécifié de l'encodage. Je suppose que je ne comprends pas ce que ASCII étant l'encodage par défaut de moyens.

MODIFIER

J'ai déplacé les modifier pour les Réponses de la section et l'a acceptée comme suggéré.

102voto

mike Points 3565

Grâce à des morceaux de différentes réponses, je pense qu'on peut piquer une explication.

En essayant d'imprimer une chaîne unicode, u'\xe9', Python, implicitement, essayez de coder que la chaîne à l'aide du schéma de codage actuellement stockés dans sys.la sortie standard stdout.l'encodage. Python fait ramasse de ce paramètre à partir de l'environnement il a été initié à partir de. Si il ne peut pas trouver un bon encodage de l'environnement, c'est alors seulement qu'il revienne à son défaut, le code ASCII.

Par exemple, j'utilise un shell bash qui l'encodage par défaut est UTF-8. Si je commence à Python, il ramasse et utiliser ce paramètre:

$ python

>>> import sys
>>> print sys.stdout.encoding
UTF-8

Supposons pour un instant quitter le Python shell et jeu de bash de l'environnement avec quelques faux encodage:

$ export LC_CTYPE=klingon
# we should get some error message here, just ignore it.

Puis démarrer l'interface python à nouveau et vérifiez qu'il ne fait que revenir à son défaut le codage ascii.

$ python

>>> import sys
>>> print sys.stdout.encoding
ANSI_X3.4-1968

Bingo!

Si vous essayez maintenant de la sortie de certains de caractères unicode à l'extérieur de l'ascii, vous devez obtenir un joli message d'erreur

>>> print u'\xe9'
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' 
in position 0: ordinal not in range(128)

Permet la sortie de Python et de jeter le shell bash.

Nous allons maintenant observer ce qui se passe après Python sorties des chaînes de caractères. Pour cela, nous allons d'abord commencer un shell bash dans un terminal graphique (j'utilise Gnome Terminal) et nous allons configurer le terminal pour décoder sortie avec de l'ISO-8859-1 alias latin-1 (graphique terminaux ont généralement une option pour Définir l'Encodage des Caractères dans un de leurs menus déroulants). Notez que cela ne change pas le réel de l'environnement de shell de l'encodage, il ne change la façon dont le terminal lui-même va décoder sortie c'est donné, un peu comme un navigateur web. Vous pouvez donc modifier le terminal de l'encodage, indépendamment de la coquille de l'environnement. Pour cela, nous allons commencer Python de la coque et de vérifier que sys.la sortie standard stdout.l'encodage est défini à l'environnement du shell de l'encodage (UTF-8 pour moi):

$ python

>>> import sys

>>> print sys.stdout.encoding
UTF-8

>>> print '\xe9' # (1)
é
>>> print u'\xe9' # (2)
é
>>> print u'\xe9'.encode('latin-1') # (3)
é
>>>

(1) python sorties chaîne binaire comme c'est, le terminal reçoit et tente de faire correspondre sa valeur avec des caractères latin-1 carte. En latin-1, 0xe9 ou 233 donne le caractère "é" et c'est ce que le terminal affiche.

(2) python tentatives implicitement encoder la chaîne Unicode avec ce régime est actuellement définie dans sys.la sortie standard stdout.l'encodage, dans ce cas c'est "UTF-8". Après l'encodage UTF-8, le binaire résultant de la chaîne "\xc3\xa9 " (voir explication plus loin). Le Terminal reçoit le flux en tant que tel et tente de décoder 0xc3a9 en latin-1, mais le latin-1 va de 0 à 255 et donc, seulement décode les flux de 1 octet à la fois. 0xc3a9 est de 2 octets de long, latin-1 décodeur donc l'interprète comme 0xc3 (195) et 0xa9 (169) et que les rendements des 2 personnages: Ã ©.

(3) python code pour point de code unicode u'\xe9' (233) avec le latin-1 schéma. S'avère latin-1 du code de points de plage va de 0 à 255 et les points à exactement le même caractère Unicode à l'intérieur de cette gamme. Par conséquent, les points de code Unicode dans cette gamme donnera la même valeur lorsqu'ils sont encodés en latin-1. Donc u'\xe9' (233) codé en latin-1, seront également les rendements de la chaîne binaire '\xe9'. Le Terminal reçoit la valeur et tente de faire correspondre sur les caractères latin-1 carte. Tout comme le cas (1), il donne des "é" et c'est ce qui est affiché.

Nous allons maintenant modifier le terminal paramètres d'encodage UTF-8 dans le menu déroulant (comme vous pouvez modifier votre navigateur web paramètres d'encodage). Pas besoin d'arrêter le Python ou le redémarrage de la coquille. Le terminal de l'encodage correspond maintenant à Python. Essayez d'imprimer à nouveau:

>>> print '\xe9' # (4)

>>> print u'\xe9' # (5)
é
>>> print u'\xe9'.encode('latin-1') # (6)

>>>

(4) python sorties d'une binaire de la chaîne. Terminal tente de décoder ce flux de données en UTF-8. Mais UTF-8 ne comprennent pas la valeur 0xe9 (voir explication plus loin) et n'est donc pas en mesure de le convertir en un point de code unicode. Pas de point de code trouvé, pas de caractère imprimé.

(5) python tentatives implicitement encoder la chaîne Unicode avec tout ce qui est dans sys.la sortie standard stdout.l'encodage. Encore "UTF-8". Le binaire résultant de la chaîne "\xc3\xa9'. Le Terminal reçoit le flux et tente de décoder 0xc3a9 également l'utilisation de l'UTF-8. Il rendements de la valeur du code 0xe9 (233), qui, sur le caractère Unicode points sur la carte pour le symbole "é". Le Terminal affiche "é".

(6) code python unicode chaîne de caractères latin-1, elle donne une chaîne binaire avec la valeur '\xe9'. Encore une fois, pour le terminal, c'est à peu près le même que le cas (4).

Conclusions: - Python sorties non-unicode chaînes de caractères comme des données brutes, sans tenir compte de son codage par défaut. Le terminal se trouve juste à afficher si son codage en cours correspondent aux données. - Python sorties des chaînes Unicode après les encoder en utilisant le programme spécifié dans sys.la sortie standard stdout.l'encodage. - Python obtient que le réglage de la coquille de l'environnement. - le terminal affiche la sortie en fonction de ses propres paramètres d'encodage. - le terminal de l'encodage est indépendante de la coque.


Plus de détails sur l'unicode, UTF-8 et en latin-1:

Unicode est en fait un tableau de caractères où quelques touches (les points de code) ont été traditionnellement attribué à point pour certains symboles. par exemple, par convention, il a été décidé que la clé 0xe9 (233) est la valeur pointant sur le symbole 'é'. ASCII et Unicode utiliser le même code de points de 0 à 127, tout comme le latin-1 et Unicode de 0 à 255. C'est, 0x41 points 'A' en ASCII, latin-1 et Unicode, 0xc8 points à 'Ü', en latin-1 et Unicode, 0xe9 points de 'é' en latin-1 et Unicode.

Lorsque vous travaillez avec des appareils électroniques, des points de code Unicode besoin d'un moyen efficace d'être représentés par voie électronique. C'est ce que le système de codage. Divers codage Unicode systèmes existent (utf7, UTF-8, UTF-16, UTF-32). Le plus intuitif et simple d'encodage approche serait d'utiliser un point de code de la valeur en Unicode carte de sa valeur par sa forme électronique, mais Unicode a actuellement plus d'un million de points de code, ce qui signifie que certains d'entre eux nécessitent de 3 octets pour être exprimé. Pour travailler efficacement avec le texte, à 1 à 1 la cartographie serait plutôt peu pratique, car il faudrait que tous les points de code être stockés dans exactement la même quantité d'espace, avec un minimum de 3 octets par caractère, quel que soit leur besoin réel.

La plupart des systèmes de codage ont des lacunes en matière de besoins d'espace, le plus économique, ce qui n'est pas de couvrir tous les points de code unicode, par exemple ascii ne couvre que la première de 128, tandis que le latin-1 couvre les 256 premiers. D'autres qui tentent d'être plus complet, il faut aussi être un gaspillage, car ils nécessitent plus d'octets que nécessaire, même pour les communes "à bas prix" des personnages. UTF-16 par exemple, utilise un minimum de 2 octets par caractère, y compris ceux de la plage ascii ('B', qui est de 65 ans, nécessite encore 2 octets en UTF-16). UTF-32 est encore plus coûteux, il stocke tous les caractères de 4 octets.

UTF-8 arrive à avoir habilement résolu le dilemme, avec un système capable de stocker des points de code avec un nombre variable d'octets espaces. Dans le cadre de sa stratégie de codage, le codage UTF-8 lacets points de code avec le drapeau bits qui indiquent (sans doute pour les décodeurs) leurs exigences en matière d'espace et de leurs limites.

L'encodage UTF-8 de points de code unicode en ascii (plage de 0 à 127):

0xxx xxxx  (in binary)
  • le x est de montrer le réel de l'espace réservé à "stocker" le point de code lors de l'encodage
  • Le 0 est un indicateur qui indique à l'UTF-8 décodeur que ce point de code n'aura besoin que de 1 octet.
  • lors de l'encodage, l'UTF-8 ne change pas la valeur de code de points dans cette gamme spécifique (c'est à dire 65 encodés en UTF-8 est également 65). Considérant que Unicode en ASCII et sont également compatibles dans la même gamme, il d'ailleurs fait l'UTF-8 et ASCII compatible également dans cette gamme.

par exemple, des points de code Unicode 'B' est '0x42" ou 0100 0010 en binaire (comme nous l'avons dit, c'est la même chose en ASCII). Après l'encodage en UTF-8, il devient:

0xxx xxxx  <-- UTF-8 encoding for Unicode code points 0 to 127
*100 0010  <-- Unicode code point 0x42
0100 0010  <-- UTF-8 encoded (exactly the same)

L'encodage UTF-8 de points de code Unicode ci-dessus 127 (non ascii):

110x xxxx 10xx xxxx            <-- (from 128 to 2047)
1110 xxxx 10xx xxxx 10xx xxxx  <-- (from 2048 to 65535)
  • le leader de bits '110' indiquer à l'UTF-8 décodeur le début d'un point de code codé sur 2 octets, alors que '1110' indique 3 octets, 11110 indiquerait 4 octets, et ainsi de suite.
  • l'intérieur '10' drapeau bits sont utilisés pour signaler le début de la intérieure d'un octet.
  • de nouveau, le x marque l'espace où le point de code Unicode valeur est stockée après l'encodage.

par exemple, 'é' point de code Unicode est 0xe9 (233).

1110 1001    <-- 0xe9

Lors de l'UTF-8 code de cette valeur, il détermine que la valeur est supérieure à 127, et moins de 2048, par conséquent, doit être codé sur 2 octets:

110x xxxx 10xx xxxx   <-- UTF-8 encoding for Unicode 128-2047
***0 0011 **10 1001   <-- 0xe9
1100 0011 1010 1001   <-- 'é' after UTF-8 encoding
C    3    A    9

Le 0xe9 des points de code Unicode après l'encodage UTF-8 devient 0xc3a9. Ce qui est exactement la façon dont le terminal reçoit. Si votre terminal est configuré pour décoder les chaînes à l'aide latin-1 (l'un des non-unicode héritage codages), vous verrez é, car il se trouve que 0xc3 en latin-1 points et à 0xa9 ©.

25voto

Mark Tolonen Points 32702

Lorsque les caractères Unicode sont imprimés à stdout, est utilisé. Un caractère non-Unicode est supposé pour être en et est juste envoyé à la borne. Sur mon système :

``n’est utilisé que lorsque le Python n’est pas une autre option.

8voto

Le Python REPL essaie de chercher quel encodage à utiliser dans votre environnement. S’il trouve quelque chose de sain alors tout fonctionne, tout simplement. C’est quand il ne peut pas savoir ce qui se passe qu’il bugs.

4voto

Mark Rushakoff Points 97350

Vous avez spécifié un encodage en entrant une chaîne Unicode explicite. Comparer les résultats de ne pas utiliser le `` préfixe.

Dans le cas de `` puis Python suppose que votre défaut de codage (Ascii), donc impression... quelque chose de vide.

0voto

user3611630 Points 26
Ça me convient

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