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 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.
Vous pouvez utiliser type
ou isinstance
.
En Python 2:
>>> type(u'abc') # Python 2 unicode string literal
<type 'unicode'>
>>> type('abc') # Python 2 byte string literal
<type 'str'>
En Python 2, str
c'est juste une séquence d'octets. Python ne sait pas quel est son encodage. Le unicode
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:
>>> type('abc') # Python 3 unicode string literal
<class 'str'>
>>> type(b'abc') # Python 3 byte string literal
<class 'bytes'>
En Python 3, str
c'est comme Python 2 unicode
et est utilisé pour stocker du texte. Ce qui était appelé str
en Python 2 est appelé bytes
en Python 3.
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)
unicode(s, "ascii")
ou quelque chose
str(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.
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:
isinstance(x, basestring)
isinstance(u"x",basestring)
revient True
.
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.
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 bytes
n'est pas défini en Python 2 et unicode
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:
# convert bytes (python 3) or unicode (python 2) to str
if 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 3
if isinstance(s, bytes):
s = s.decode('ascii') # or s = str(s)[2:-1]
else:
# for Python 2
if isinstance(s, unicode):
s = str(s)
Ce sont tous deux impythoniques, et la plupart du temps, il y a probablement une meilleure façon.
six
et de tester contre six.binary_type
etsix.text_type
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,
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 Unicode
str
s sont des collections ordonnées de caractères Unicode
Le 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:
"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
La même méthode pour les distinguer est utilisée.
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')
except TypeError:
try:
return str(s).encode('utf-8')
except AttributeError:
return s
except AttributeError:
return s
return s # assume it was already utf-8
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.
Pour la compatibilité py2 / py3, utilisez simplement
import six
if isinstance(obj, six.text_type)
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 en unicode
un, vous pouvez:
import builtins
i = 'cats'
if 'unicode' in dir(builtins): # True in python 2, False in 3
i = unicode(i)