Plus important encore, pourquoi devriez-vous vous en soucier?
Johnsyweb
@Johnsyweb En raison de{UnicodeDecodeError} 'ascii' codec can't decode byte 0xc2
alex
Réponses:
295
En Python 3, toutes les chaînes sont des séquences de caractères Unicode. Il existe un bytestype qui contient des octets bruts.
En Python 2, une chaîne peut être de type strou de type unicode. Vous pouvez dire quel code quelque chose comme ceci:
def whatisthis(s):if isinstance(s, str):print"ordinary string"elif isinstance(s, unicode):print"unicode string"else:print"not a string"
Cela ne distingue pas "Unicode ou ASCII"; il distingue uniquement les types Python. Une chaîne Unicode peut être constituée uniquement de caractères dans la plage ASCII, et un sous-test peut contenir des données ASCII, Unicode codées ou même des données non textuelles.
En Python 2, strc'est juste une séquence d'octets. Python ne sait pas quel est son encodage. Le unicodetype est le moyen le plus sûr de stocker du texte. Si vous voulez mieux comprendre cela, je recommande http://farmdev.com/talks/unicode/ .
En Python 3, strc'est comme Python 2 unicodeet est utilisé pour stocker du texte. Ce qui était appelé stren Python 2 est appelé bytesen Python 3.
Comment savoir si une chaîne d'octets est valide utf-8 ou ascii
Vous pouvez appeler decode. S'il déclenche une exception UnicodeDecodeError, il n'est pas valide.
>>> u_umlaut = b'\xc3\x9c'# UTF-8 representation of the letter 'Ü'>>> u_umlaut.decode('utf-8')
u'\xdc'>>> u_umlaut.decode('ascii')Traceback(most recent call last):File"<stdin>", line 1,in<module>UnicodeDecodeError:'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
Juste pour la référence des autres - str.decode n'existe pas en python 3. On dirait que vous devez unicode(s, "ascii")ou quelque chose
Shadow
3
Désolé, je voulais direstr(s, "ascii")
Shadow
1
Ce n'est pas exact pour python 3
ProsperousHeart
2
@ProsperousHeart Mis à jour pour couvrir Python 3. Et pour essayer d'expliquer la différence entre les bytestrings et les chaînes unicode.
Mikel
44
En python 3.x, toutes les chaînes sont des séquences de caractères Unicode. et faire la vérification isinstance de str (ce qui signifie une chaîne unicode par défaut) devrait suffire.
isinstance(x, str)
En ce qui concerne python 2.x, la plupart des gens semblent utiliser une instruction if qui comporte deux vérifications. un pour str et un pour unicode.
Si vous souhaitez vérifier si vous avez un objet "semblable à une chaîne" avec une seule instruction, vous pouvez effectuer les opérations suivantes:
C'est faux. En Python 2.7 isinstance(u"x",basestring)revient True.
PythonNut
11
@PythonNut: Je crois que c'était le point. L'utilisation de isinstance (x, basestring) suffit pour remplacer les deux tests distincts ci-dessus.
KQ.
5
C'est utile dans de nombreux cas, mais ce n'est évidemment pas ce que le questionneur voulait dire.
mhsmith
3
C'est la réponse à la question. Tous les autres ont mal compris ce qu'OP a dit et ont donné des réponses génériques sur la vérification de type en Python.
fiatjaf
1
Ne répond pas à la question d'OP. Le titre de la question (seul) POURRAIT être interprété de telle sorte que cette réponse soit correcte. Cependant, OP dit spécifiquement «comprendre lequel» dans la description de la question, et cette réponse ne répond pas à cela.
MD004
31
Unicode n'est pas un encodage - pour citer Kumar McMillan:
Si ASCII, UTF-8 et les autres chaînes d'octets sont du "texte" ...
... alors Unicode est "text-ness";
c'est la forme abstraite du texte
Lisez Unicode In Python de McMillan , un discours complètement démystifié de PyCon 2008, il explique les choses beaucoup mieux que la plupart des réponses connexes sur Stack Overflow.
Ces diapositives sont probablement la meilleure introduction à Unicode que j'ai rencontrée à ce jour
Jonny
23
Si vos besoins de code pour être compatibles avec les deux Python 2 et Python 3, vous ne pouvez pas utiliser directement des choses comme isinstance(s,bytes)ou isinstance(s,unicode)sans les envelopper dans les deux try / except ou un test de la version python, parce que bytesn'est pas défini en Python 2 et unicodeest indéfini en Python 3 .
Il existe des solutions de contournement laides. Un très laid est de comparer le nom du type, au lieu de comparer le type lui-même. Voici un exemple:
# convert bytes (python 3) or unicode (python 2) to strif str(type(s))=="<class 'bytes'>":# only possible in Python 3
s = s.decode('ascii')# or s = str(s)[2:-1]elif str(type(s))=="<type 'unicode'>":# only possible in Python 2
s = str(s)
Une solution de contournement sans doute un peu moins laide consiste à vérifier le numéro de version de Python, par exemple:
if sys.version_info >=(3,0,0):# for Python 3if isinstance(s, bytes):
s = s.decode('ascii')# or s = str(s)[2:-1]else:# for Python 2if isinstance(s, unicode):
s = str(s)
Ce sont tous deux impythoniques, et la plupart du temps, il y a probablement une meilleure façon.
La meilleure façon est probablement d'utiliser sixet de tester contre six.binary_typeetsix.text_type
Ian Clelland
1
Vous pouvez utiliser des types .__ nom__ pour sonder les noms de type.
Paulo Freitas
Je ne suis pas tout à fait sûr du cas d'utilisation de ce morceau de code, sauf en cas d'erreur logique. Je pense qu'il devrait y avoir un "non" dans le code python 2. Sinon, vous convertissez tout en chaînes unicode pour Python 3 et l'inverse pour Python 2!
oligofren
Oui, oligofren, c'est ce qu'il fait. Les chaînes internes standard sont Unicode en Python 3 et ASCII en Python 2. Les extraits de code convertissent donc le texte en type de chaîne interne standard (que ce soit Unicode ou ASCII).
Dave Burton
12
utilisation:
import six
if isinstance(obj, six.text_type)
à l'intérieur de la bibliothèque six, il est représenté comme:
if PY3:
string_types = str,else:
string_types = basestring,
ça devrait l'être if isinstance(obj, six.text_type) . Mais oui, c'est la bonne réponse.
karantan
Ne répond pas à la question d'OP. Le titre de la question (seul) POURRAIT être interprété de telle sorte que cette réponse soit correcte. Cependant, OP dit spécifiquement «comprendre lequel» dans la description de la question, et cette réponse ne répond pas à cela.
MD004
4
Notez que sur Python 3, il n'est pas vraiment juste de dire:
strs sont UTFx pour tout x (par exemple UTF8)
strs sont Unicode
strs sont des collections ordonnées de caractères Unicode
Le strtype de Python est (normalement) une séquence de points de code Unicode, dont certains sont mappés sur des caractères.
Même sur Python 3, il n'est pas aussi simple de répondre à cette question que vous pourriez l'imaginer.
Une façon évidente de tester les chaînes compatibles ASCII est par une tentative de codage:
"Hello there!".encode("ascii")#>>> b'Hello there!'"Hello there... ☃!".encode("ascii")#>>> Traceback (most recent call last):#>>> File "", line 4, in <module>#>>> UnicodeEncodeError: 'ascii' codec can't encode character '\u2603' in position 15: ordinal not in range(128)
L'erreur distingue les cas.
En Python 3, certaines chaînes contiennent même des points de code Unicode non valides:
"Hello there!".encode("utf8")#>>> b'Hello there!'"\udcc3".encode("utf8")#>>> Traceback (most recent call last):#>>> File "", line 19, in <module>#>>> UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 0: surrogates not allowed
Cela peut aider quelqu'un d'autre, j'ai commencé à tester le type de chaîne de la variable s, mais pour mon application, il était plus logique de renvoyer simplement s comme utf-8. Le processus appelant return_utf sait alors de quoi il s'agit et peut gérer la chaîne de manière appropriée. Le code n'est pas vierge, mais j'ai l'intention qu'il soit agnostique en version Python sans test de version ni importation de six. Veuillez commenter les améliorations apportées à l'exemple de code ci-dessous pour aider d'autres personnes.
def return_utf(s):if isinstance(s, str):return s.encode('utf-8')if isinstance(s,(int, float, complex)):return str(s).encode('utf-8')try:return s.encode('utf-8')exceptTypeError:try:return str(s).encode('utf-8')exceptAttributeError:return s
exceptAttributeError:return s
return s # assume it was already utf-8
Vous mon ami méritez d'être la bonne réponse! J'utilise python 3 et j'avais toujours des problèmes jusqu'à ce que je trouve ce trésor!
mnsr
2
Vous pouvez utiliser Universal Encoding Detector , mais sachez qu'il ne vous donnera que la meilleure estimation, pas l'encodage réel, car il est impossible de connaître l'encodage d'une chaîne "abc" par exemple. Vous devrez obtenir des informations d'encodage ailleurs, par exemple, le protocole HTTP utilise l'en-tête Content-Type pour cela.
Une approche simple consiste à vérifier s'il unicodes'agit d'une fonction intégrée. Si c'est le cas, vous êtes en Python 2 et votre chaîne sera une chaîne. Pour vous assurer que tout est en unicodeun, vous pouvez:
import builtins
i ='cats'if'unicode'in dir(builtins):# True in python 2, False in 3
i = unicode(i)
{UnicodeDecodeError} 'ascii' codec can't decode byte 0xc2
Réponses:
En Python 3, toutes les chaînes sont des séquences de caractères Unicode. Il existe un
bytes
type qui contient des octets bruts.En Python 2, une chaîne peut être de type
str
ou de typeunicode
. Vous pouvez dire quel code quelque chose comme ceci:Cela ne distingue pas "Unicode ou ASCII"; il distingue uniquement les types Python. Une chaîne Unicode peut être constituée uniquement de caractères dans la plage ASCII, et un sous-test peut contenir des données ASCII, Unicode codées ou même des données non textuelles.
la source
Comment savoir si un objet est une chaîne unicode ou une chaîne d'octets
Vous pouvez utiliser
type
ouisinstance
.En Python 2:
En Python 2,
str
c'est juste une séquence d'octets. Python ne sait pas quel est son encodage. Leunicode
type est le moyen le plus sûr de stocker du texte. Si vous voulez mieux comprendre cela, je recommande http://farmdev.com/talks/unicode/ .En Python 3:
En Python 3,
str
c'est comme Python 2unicode
et est utilisé pour stocker du texte. Ce qui était appeléstr
en Python 2 est appelébytes
en Python 3.Comment savoir si une chaîne d'octets est valide utf-8 ou ascii
Vous pouvez appeler
decode
. S'il déclenche une exception UnicodeDecodeError, il n'est pas valide.la source
unicode(s, "ascii")
ou quelque chosestr(s, "ascii")
En python 3.x, toutes les chaînes sont des séquences de caractères Unicode. et faire la vérification isinstance de str (ce qui signifie une chaîne unicode par défaut) devrait suffire.
En ce qui concerne python 2.x, la plupart des gens semblent utiliser une instruction if qui comporte deux vérifications. un pour str et un pour unicode.
Si vous souhaitez vérifier si vous avez un objet "semblable à une chaîne" avec une seule instruction, vous pouvez effectuer les opérations suivantes:
la source
isinstance(u"x",basestring)
revientTrue
.Unicode n'est pas un encodage - pour citer Kumar McMillan:
Lisez Unicode In Python de McMillan , un discours complètement démystifié de PyCon 2008, il explique les choses beaucoup mieux que la plupart des réponses connexes sur Stack Overflow.
la source
Si vos besoins de code pour être compatibles avec les deux Python 2 et Python 3, vous ne pouvez pas utiliser directement des choses comme
isinstance(s,bytes)
ouisinstance(s,unicode)
sans les envelopper dans les deux try / except ou un test de la version python, parce quebytes
n'est pas défini en Python 2 etunicode
est indéfini en Python 3 .Il existe des solutions de contournement laides. Un très laid est de comparer le nom du type, au lieu de comparer le type lui-même. Voici un exemple:
Une solution de contournement sans doute un peu moins laide consiste à vérifier le numéro de version de Python, par exemple:
Ce sont tous deux impythoniques, et la plupart du temps, il y a probablement une meilleure façon.
la source
six
et de tester contresix.binary_type
etsix.text_type
utilisation:
à l'intérieur de la bibliothèque six, il est représenté comme:
la source
if isinstance(obj, six.text_type)
. Mais oui, c'est la bonne réponse.Notez que sur Python 3, il n'est pas vraiment juste de dire:
str
s sont UTFx pour tout x (par exemple UTF8)str
s sont Unicodestr
s sont des collections ordonnées de caractères UnicodeLe
str
type de Python est (normalement) une séquence de points de code Unicode, dont certains sont mappés sur des caractères.Même sur Python 3, il n'est pas aussi simple de répondre à cette question que vous pourriez l'imaginer.
Une façon évidente de tester les chaînes compatibles ASCII est par une tentative de codage:
L'erreur distingue les cas.
En Python 3, certaines chaînes contiennent même des points de code Unicode non valides:
La même méthode pour les distinguer est utilisée.
la source
Cela peut aider quelqu'un d'autre, j'ai commencé à tester le type de chaîne de la variable s, mais pour mon application, il était plus logique de renvoyer simplement s comme utf-8. Le processus appelant return_utf sait alors de quoi il s'agit et peut gérer la chaîne de manière appropriée. Le code n'est pas vierge, mais j'ai l'intention qu'il soit agnostique en version Python sans test de version ni importation de six. Veuillez commenter les améliorations apportées à l'exemple de code ci-dessous pour aider d'autres personnes.
la source
Vous pouvez utiliser Universal Encoding Detector , mais sachez qu'il ne vous donnera que la meilleure estimation, pas l'encodage réel, car il est impossible de connaître l'encodage d'une chaîne "abc" par exemple. Vous devrez obtenir des informations d'encodage ailleurs, par exemple, le protocole HTTP utilise l'en-tête Content-Type pour cela.
la source
Pour la compatibilité py2 / py3, utilisez simplement
import six if isinstance(obj, six.text_type)
la source
Une approche simple consiste à vérifier s'il
unicode
s'agit d'une fonction intégrée. Si c'est le cas, vous êtes en Python 2 et votre chaîne sera une chaîne. Pour vous assurer que tout est enunicode
un, vous pouvez:la source