110 votes

Types str et unicode en Python

Travaillant avec Python 2.7, je me demande quel avantage réel il y a à utiliser le type unicode au lieu de str car ils semblent tous deux capables de contenir des chaînes de caractères Unicode. Existe-t-il une raison particulière, hormis la possibilité de définir des codes Unicode dans les fichiers unicode chaînes de caractères en utilisant le caractère d'échappement \ ? :

Exécution d'un module avec :

# -*- coding: utf-8 -*-

a = 'á'
ua = u'á'
print a, ua

Résultats dans : á, á

EDITAR:

Plus de tests en utilisant le shell Python :

>>> a = 'á'
>>> a
'\xc3\xa1'
>>> ua = u'á'
>>> ua
u'\xe1'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> ua
u'\xe1'

Donc, le unicode semble être codée en utilisant latin1 au lieu de utf-8 et la chaîne brute est encodée en utilisant utf-8 ? Je suis encore plus confus maintenant ! :S

186voto

Bakuriu Points 22607

unicode est destiné à gérer texte . Le texte est une séquence de points de code dont peut être plus grand qu'un seul octet . Le texte peut être encodé dans un encodage spécifique pour représenter le texte sous forme d'octets bruts (par ex. utf-8 , latin-1 ...).

Notez que unicode n'est pas encodé ! La représentation interne utilisée par python est un détail d'implémentation, et vous ne devriez pas vous en soucier tant qu'elle est capable de représenter les points de code que vous souhaitez.

Au contraire str en Python 2 est une séquence simple de octets . Il ne représente pas un texte !

Vous pouvez penser à unicode comme une représentation générale d'un certain texte, qui peut être codé de nombreuses façons différentes en une séquence de données binaires représentée par l'intermédiaire de str .

Remarque : dans Python 3, unicode a été renommé en str et il y a un nouveau bytes pour une séquence d'octets en clair.

Quelques différences que vous pouvez voir :

>>> len(u'à')  # a single code point
1
>>> len('à')   # by default utf-8 -> takes two bytes
2
>>> len(u'à'.encode('utf-8'))
2
>>> len(u'à'.encode('latin1'))  # in latin1 it takes one byte
1
>>> print u'à'.encode('utf-8')  # terminal encoding is utf-8
à
>>> print u'à'.encode('latin1') # it cannot understand the latin1 byte

Notez que l'utilisation de str vous avez un contrôle de niveau inférieur sur les octets individuels d'une représentation d'encodage spécifique, alors que l'utilisation de unicode que vous ne pouvez contrôler qu'au niveau du point de code. Par exemple, vous pouvez le faire :

>>> 'àèìòù'
'\xc3\xa0\xc3\xa8\xc3\xac\xc3\xb2\xc3\xb9'
>>> print 'àèìòù'.replace('\xa8', '')
àìòù

Ce qui était auparavant un UTF-8 valide, ne l'est plus. En utilisant une chaîne unicode, vous ne pouvez pas opérer de manière à ce que la chaîne résultante ne soit pas un texte unicode valide. Vous pouvez supprimer un point de code, remplacer un point de code par un autre, etc., mais vous ne pouvez pas modifier la représentation interne.

54voto

weibeld Points 1530

Unicode et les encodages sont des choses complètement différentes et sans rapport.

Unicode

Attribue un ID numérique à chaque caractère :

  • 0x41 A
  • 0xE1 á
  • 0x414

Ainsi, Unicode attribue le nombre 0x41 à A, 0xE1 à á, et 0x414 à .

Même la petite flèche que j'ai utilisée a son numéro Unicode, c'est 0x2192. Et même les emojis ont leur numéro Unicode, c'est 0x1F602.

Vous pouvez consulter les numéros Unicode de tous les caractères dans la base de données de la Commission européenne. ce tableau . En particulier, vous pouvez trouver les trois premiers caractères ci-dessus ici la flèche ici et l'emoji ici .

Ces numéros assignés à tous les caractères par Unicode sont appelés points de code .

Le but de tout ceci est de fournir un moyen de se référer sans ambiguïté à chaque caractère. Par exemple, si je parle de , au lieu de dire "tu sais, cet emoji qui rit avec des larmes" je peux juste dire, Point de code Unicode 0x1F602 . Plus facile, non ?

Notez que les points de code Unicode sont généralement formatés avec un caractère de tête U+ puis la valeur numérique hexadécimale complétée par au moins 4 chiffres. Ainsi, les exemples ci-dessus seraient U+0041, U+00E1, U+0414, U+2192, U+1F602.

Les points de code Unicode vont de U+0000 à U+10FFFF. Cela représente 1 114 112 numéros. 2048 de ces nombres sont utilisés pour substituts Il reste donc 1 112 064 personnes. Cela signifie qu'Unicode peut attribuer un identifiant unique (point de code) à 1 112 064 caractères distincts. Tous ces points de code ne sont pas encore attribués à un caractère, et Unicode est étendu en permanence (par exemple, lorsque de nouveaux emojis sont introduits).

Ce qu'il faut retenir, c'est que tout ce que fait Unicode, c'est d'attribuer un identifiant numérique, appelé point de code, à chaque caractère pour une référence facile et sans ambiguïté.

Encodages

Faire correspondre des caractères à des modèles binaires.

Ces modèles de bits sont utilisés pour représenter les caractères dans la mémoire de l'ordinateur ou sur le disque.

Il existe de nombreux codages différents qui couvrent différents sous-ensembles de caractères. Dans le monde anglophone, les codages les plus courants sont les suivants :

ASCII

Cartes 128 caractères (points de code U+0000 à U+007F) à des modèles binaires de longueur 7.

Exemple :

  • a 1100001 (0x61)

Vous pouvez voir tous les mappings dans ce document. tableau .

ISO 8859-1 (alias Latin-1)

Cartes 191 caractères (points de code U+0020 à U+007E et U+00A0 à U+00FF) à des modèles binaires de longueur 8.

Exemple :

  • a 01100001 (0x61)
  • á 11100001 (0xE1)

Vous pouvez voir tous les mappings dans ce document. tableau .

UTF-8

Cartes 1 112 064 caractères (tous les points de code Unicode existants) à des modèles binaires de 8, 16, 24 ou 32 bits (c'est-à-dire 1, 2, 3 ou 4 octets).

Exemple :

  • a 01100001 (0x61)
  • á 11000011 10100001 (0xC3 0xA1)
  • 11100010 10001001 10100000 (0xE2 0x89 0xA0)
  • 11110000 10011111 10011000 10000010 (0xF0 0x9F 0x98 0x82)

La façon dont UTF-8 encode les caractères en chaînes de bits est très bien décrite. ici .

Unicode et encodages

En examinant les exemples ci-dessus, on comprend l'utilité d'Unicode.

Par exemple, si je suis Latin-1 et que je veux expliquer mon codage de á, je n'ai pas besoin de le dire :

"J'encode ce a avec un aigu (ou comment vous appelez cette barre montante) comme 11100001"

Mais je peux juste dire :

"Je code U+00E1 comme 11100001"

Et si je suis UTF-8 je peux dire :

"Moi, à mon tour, je code U+00E1 comme 11000011 10100001"

Et tout le monde sait sans ambiguïté de quel personnage il s'agit.

Venons-en maintenant à la confusion qui s'installe souvent

Il est vrai que, parfois, la configuration binaire d'un encodage, si on l'interprète comme un nombre binaire, est la même que le point de code Unicode de ce caractère.

Par exemple :

  • L'ASCII code a comme 1100001, que vous pouvez interpréter comme le nombre hexadécimal 0x61 et le point de code Unicode de a es U+0061 .
  • Le latin-1 code á comme 11100001, que vous pouvez interpréter comme le nombre hexadécimal 0xE1 et le point de code Unicode de á es U+00E1 .

Bien sûr, cela a été arrangé ainsi exprès pour des raisons de commodité. Mais vous devriez le considérer comme un pure coïncidence . La configuration binaire utilisée pour représenter un caractère en mémoire n'est en aucun cas liée au point de code Unicode de ce caractère.

Personne ne dit même que vous devez interpréter une chaîne de bits comme 11100001 comme un nombre binaire. Il suffit de la regarder comme la séquence de bits que le Latin-1 utilise pour coder le caractère á .

Retour à votre question

Le codage utilisé par votre interpréteur Python est le suivant UTF-8 .

Voici ce qui se passe dans vos exemples :

Exemple 1

Le texte suivant encode le caractère á en UTF-8. Il en résulte la chaîne de bits 11000011 10100001, qui est enregistrée dans la variable a .

>>> a = 'á'

Quand vous regardez la valeur de a son contenu 11000011 10100001 est formaté en tant que nombre hexadécimal 0xC3 0xA1 et sorti comme suit '\xc3\xa1' :

>>> a
'\xc3\xa1'

Exemple 2

Le texte suivant enregistre le point de code Unicode de á, qui est U+00E1, dans la variable ua (nous ne savons pas quel format de données Python utilise en interne pour représenter le point de code U+00E1 en mémoire, et c'est sans importance pour nous) :

>>> ua = u'á'

Quand vous regardez la valeur de ua Python vous indique qu'il contient le point de code U+00E1 :

>>> ua
u'\xe1'

Exemple 3

L'exemple suivant encode le point de code Unicode U+00E1 (représentant le caractère á) avec UTF-8, ce qui donne le motif binaire 11000011 10100001. Là encore, pour la sortie, ce motif binaire est représenté par le nombre hexadécimal 0xC3 0xA1 :

>>> ua.encode('utf-8')
'\xc3\xa1'

Exemple 4

L'exemple suivant code le point de code Unicode U+00E1 (représentant le caractère á) avec Latin-1, ce qui donne le motif binaire 11100001. Pour la sortie, ce motif binaire est représenté par le nombre hexadécimal 0xE1, qui par coïncidence est le même que le point de code initial U+00E1 :

>>> ua.encode('latin1')
'\xe1'

Il n'y a pas de relation entre l'objet Unicode ua et l'encodage Latin-1. Le fait que le point de code de á soit U+00E1 et que le codage Latin-1 de á soit 0xE1 (si l'on interprète le schéma binaire du codage comme un nombre binaire) est une pure coïncidence.

33voto

Martijn Pieters Points 271458

Il se trouve que votre terminal est configuré en UTF-8.

Le fait que l'impression a fonctionne est une coïncidence ; vous écrivez des octets UTF-8 bruts dans le terminal. a est une valeur de longueur deux contenant deux octets, les valeurs hexagonales C3 et A1, alors que ua est une valeur unicode de longueur un contenant un point de code U+00E1.

Cette différence de longueur est une raison majeure pour utiliser les valeurs Unicode ; vous ne pouvez pas facilement mesurer le nombre de texte caractères dans une chaîne d'octets ; le len() d'une chaîne d'octets vous indique combien d'octets ont été utilisés, et non combien de caractères ont été encodés.

Vous pouvez voir la différence lorsque vous encoder la valeur unicode à différents encodages de sortie :

>>> a = 'á'
>>> ua = u'á'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> a
'\xc3\xa1'

Notez que les 256 premiers points de code de la norme Unicode correspondent à la norme Latin 1, de sorte que le point de code U+00E1 est codé en Latin 1 comme un octet avec la valeur hexagonale E1.

En outre, Python utilise des codes d'échappement dans les représentations de l'unicode et des chaînes d'octets, et les points de code bas qui ne sont pas de l'ASCII imprimable sont représentés à l'aide de la fonction \x.. les valeurs d'échappement également. C'est pourquoi une chaîne Unicode dont le point de code est compris entre 128 et 255 a l'aspect suivant juste comme l'encodage Latin 1. Si vous avez une chaîne unicode avec des points de code au-delà de U+00FF, il faut utiliser une séquence d'échappement différente, \u.... est utilisé à la place, avec une valeur hexadécimale à quatre chiffres.

Il semble que vous n'ayez pas encore bien compris la différence entre Unicode et un encodage. Veuillez lire les articles suivants avant de continuer :

2voto

Ali Rasim Kocal Points 510

Lorsque vous définissez a comme unicode, les caractères a et á sont égaux. Sinon, á compte comme deux caractères. Essayez len(a) et len(au). En plus de cela, vous pouvez avoir besoin de l'encodage lorsque vous travaillez avec d'autres environnements. Par exemple, si vous utilisez md5, vous obtenez des valeurs différentes pour a et ua

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