web-dev-qa-db-fra.com

Python str vs types Unicode

En travaillant avec Python 2.7, je me demande quel avantage il ya à utiliser le type unicode au lieu de str, car ils semblent tous deux capables de contenir des chaînes Unicode. Existe-t-il une raison particulière en dehors de la possibilité de définir des codes Unicode dans les chaînes unicode à l'aide du caractère d'échappement \?:

Exécuter un module avec:

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

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

Résultats en: á, á

MODIFIER:

Plus de tests en utilisant Python Shell:

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

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

97
Caumons

unicode est destiné à gérer le texte . Le texte est une séquence de points de code qui peut être plus grand qu'un seul octet . Le texte peut être codé dans un codage spécifique pour représenter le texte sous forme d'octets bruts (par exemple, 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; 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 dans Python 2 est une simple séquence d'octets . Cela ne représente pas du texte!

Vous pouvez considérer unicode comme une représentation générale d'un texte pouvant être codé de différentes manières dans une séquence de données binaires représentée via str.

Remarque: Dans Python 3, unicode a été renommé en str et il existe un nouveau type bytes pour une séquence simple de octets

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 qu'en utilisant str vous disposez d'un contrôle de niveau inférieur sur les octets simples d'une représentation de codage spécifique, alors que vous utilisez unicode, vous ne pouvez contrôler qu'au niveau du point de code. Par exemple, vous pouvez faire:

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

Ce qui était auparavant valide UTF-8 ne l'est plus. Si vous utilisez une chaîne unicode, vous ne pouvez pas utiliser une chaîne telle 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 jouer avec la représentation interne.

169
Bakuriu

Votre terminal se trouve être configuré sur UTF-8.

Le fait d’imprimer a oeuvres est une coïncidence; vous écrivez des octets UTF-8 bruts sur le terminal. a est une valeur de longueur deux , contenant deux octets, valeurs hexadécimales C3 et A1, tandis que ua est une valeur unicode de longueur un , contenant un point de code U + 00E1.

Cette différence de longueur est l'une des principales raisons d'utiliser des valeurs Unicode; vous ne pouvez pas facilement mesurer le nombre de caractères text dans une chaîne d'octets; la len() d'une chaîne d'octets vous indique le nombre d'octets utilisés et non le nombre de caractères encodés.

Vous pouvez voir la différence lorsque vous encodez la valeur unicode en 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 sous forme d'octet de valeur hexadécimale E1.

De plus, Python utilise les codes d'échappement dans les représentations de chaînes unicode et d'octets, et les points de code faibles qui ne sont pas imprimables ASCII sont également représentés à l'aide de \x... C'est pourquoi une chaîne Unicode avec un point de code compris entre 128 et 255 ressemble à juste au même codage que Latin 1. Si vous avez une chaîne unicode avec des points de code au-delà de U + 00FF, une séquence d'échappement différente, \u.... est utilisé à la place, avec une valeur hexadécimale à quatre chiffres.

Il semble que vous ne compreniez pas encore parfaitement la différence entre Unicode et un encodage. Veuillez lire les articles suivants avant de continuer:

29
Martijn Pieters

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

Unicode

Attribue un identifiant 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 leurs numéros Unicode, ???? est 0x1F602.

Vous pouvez rechercher les numéros Unicode de tous les caractères dans cette table . En particulier, vous pouvez trouver les trois premiers caractères ci-dessus ici , la flèche ici , et l’emoji ici .

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

Le but de tout cela 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 "vous savez, cet émoji qui rit avec des larmes" , je peux simplement dire Point de code Unicode 0x1F602 . Plus facile, non?

Notez que les points de code Unicode sont généralement formatés avec un U+ en tête, puis que la valeur numérique hexadécimale est complétée avec 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. C'est 1.114.112 numéros. 2048 de ces nombres sont utilisés pour mères porteuses , il reste donc 1 112 064. Cela signifie que Unicode peut attribuer un ID 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 émojis sont introduits).

L'important, c'est que tout ce que Unicode fait est d'attribuer un identifiant numérique, appelé point de code, à chaque caractère pour une référence facile et non ambiguë.

Codages

Mappez les caractères en motifs.

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 encodages couvrant 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) en séquences de bits de longueur 7.

Exemple:

  • a → 1100001 (0x61)

Vous pouvez voir tous les mappages dans ce table .

ISO 8859-1 (aka Latin-1)

Mappe 191 caractères (points de code U + 0020 à U + 007E et U + 00A0 à U + 00FF) en séquences de bits de longueur 8.

Exemple:

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

Vous pouvez voir tous les mappages dans ce table .

TF-8

Mappe 1 112 064 caractères (tous les points de code Unicode existants) en modèles de bits d'une longueur 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 manière dont UTF-8 code les caractères en chaînes de bits est très bien décrite ici .

Unicode et codages

En regardant les exemples ci-dessus, il devient clair comment Unicode est utile.

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

"Je code cela 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 clairement de quel personnage il s'agit.

Maintenant à la confusion qui surgit souvent

Il est vrai que, parfois, le motif binaire d'un codage, si vous l'interprétez comme un nombre binaire, est identique au point de code Unicode de ce caractère.

Par exemple:

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

Bien entendu, cela a été arrangé comme cela exprès pour des raisons pratiques. Mais vous devriez le voir comme une pure coïncidence . Le modèle de bits utilisé pour représenter un caractère en mémoire n'est aucunement lié 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 regarder cela comme la séquence de bits utilisée par Latin-1 pour encoder le caractère á .

Retour à votre question

Le codage utilisé par votre interprète Python est UTF-8 .

Voici ce qui se passe dans vos exemples:

Exemple 1

Ce qui suit code 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 = 'á'

Lorsque vous examinez la valeur de a, son contenu 11000011 10100001 est formaté sous la forme du nombre hexadécimal 0xC3 0xA1 et sorti en tant que '\xc3\xa1':

>>> a
'\xc3\xa1'

Exemple 2

Ce qui suit 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'á'

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

>>> ua
u'\xe1'

Exemple 3

Ce qui suit code le point de code Unicode U + 00E1 (représentant le caractère á) avec UTF-8, ce qui donne le motif de bits 11000011 10100001. De nouveau, ce motif de bits est représenté par le nombre hexadécimal 0xC3 0xA1:

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

Exemple 4

Ce qui suit code le point de code Unicode U + 00E1 (représentant le caractère á) avec Latin-1, ce qui donne le motif de bits 11100001. Pour la sortie, ce motif de bits est représenté par le nombre hexadécimal 0xE1, qui par coïncidence est identique au point de code initial U + 00E1:

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

Il n'y a pas de relation entre l'objet Unicode ua et le codage Latin-1. Le fait que le point de code de á soit U + 00E1 et que le codage en latin-1 de á soit 0xE1 (si vous interprétez la structure de bits du codage comme un nombre binaire) est une pure coïncidence.

25
weibeld

Lorsque vous définissez un en tant qu'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 devrez peut-être encoder lorsque vous travaillez avec d'autres environnements. Par exemple, si vous utilisez md5, vous obtenez différentes valeurs pour a et ua

2
Ali Rasim Kocal