web-dev-qa-db-fra.com

Comment vérifier si une chaîne est unicode ou ascii?

Que dois-je faire dans Python pour déterminer le codage d'une chaîne?

250
TIMEX

Dans Python 3, toutes les chaînes sont des séquences de caractères Unicode. Il existe un type bytes qui contient des octets bruts.

Dans Python 2, une chaîne peut être de type str ou de type unicode. Vous pouvez dire à l'aide de 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 ne distingue que les types Python. Une chaîne Unicode peut être constituée uniquement de caractères compris dans la plage ASCII et une chaîne d'octets peut contenir des données ASCII, Unicode codé ou même des données non textuelles.

270
Greg Hewgill

Comment savoir si un objet est une chaîne unicode ou une chaîne d'octets

Vous pouvez utiliser type ou isinstance.

Dans Python 2:

>>> type(u'abc')  # Python 2 unicode string literal
<type 'unicode'>
>>> type('abc')   # Python 2 byte string literal
<type 'str'>

Dans Python 2, str n'est qu'une séquence d'octets. Python ne sait pas quel est son encodage. Le type unicode est le moyen le plus sûr de stocker du texte. Si vous voulez comprendre davantage, je recommande http://farmdev.com/talks/unicode/ .

Dans Python 3:

>>> type('abc')   # Python 3 unicode string literal
<class 'str'>
>>> type(b'abc')  # Python 3 byte string literal
<class 'bytes'>

Dans Python 3, str ressemble à Python 2 unicode et permet de stocker du texte. Ce qui s'appelait str dans Python 2 s'appelle bytes dans Python 3.


Comment savoir si une chaîne d'octets est valide utf-8 ou ascii

Vous pouvez appeler decode. Si elle déclenche une exception UnicodeDecodeError, ce 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)
111
Mikel

Dans python 3.x, toutes les chaînes sont des séquences de caractères Unicode. et faire la vérification isinstance pour 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 comportant deux vérifications. un pour str et un pour unicode.

Si vous voulez vérifier si vous avez un objet 'ressemblant à une chaîne' avec une seule instruction, vous pouvez procéder comme suit:

isinstance(x, basestring)
43
ThinkBonobo

Unicode n'est pas un encodage - pour citer Kumar McMillan:

Si ASCII, UTF-8 et d'autres chaînes d'octets sont "text" ...

... alors Unicode est "text-ness";

c'est la forme abstraite du texte

Prenez connaissance de la conversation Unicode de McMillan en Python, complètement démystifiée de PyCon 2008, qui explique beaucoup mieux que la plupart des réponses connexes sur Stack Overflow.

31
Alex Dean

Si votre code doit être compatible avec les deux Python 2 et Python 3, vous ne pouvez pas utiliser directement des éléments tels que isinstance(s,bytes) ou isinstance(s,unicode) sans les insérer dans try/except ou dans un test de version python, car bytes n'est pas défini dans Python 2 et unicode n'est pas défini dans Python 3.

Il existe des solutions de contournement laides. Une très laide consiste à 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 légèrement moins laide consiste à vérifier le numéro de version 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 les deux non rythmiques, et la plupart du temps, il y a probablement une meilleure solution.

22
Dave Burton

utilisation:

import six
if isinstance(obj, six.text_type)

à l'intérieur des six bibliothèques, il est représenté par:

if PY3:
    string_types = str,
else:
    string_types = basestring,
10
madjardi

Notez que sur Python 3, il n'est pas vraiment juste de dire:

  • strs sont UTFx pour tout x (par exemple UTF8)

  • strs sont en Unicode

  • strs sont des collections ordonnées de caractères Unicode

Le type str de Python est (normalement) une séquence de points de code Unicode, dont certains correspondent à des caractères.


Même sur Python 3, il n'est pas aussi simple de répondre à cette question que vous pourriez l'imaginer.

Un moyen évident de tester les chaînes compatibles ASCII consiste à tenter un encodage:

"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.

Dans 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.

4
Veedrac

Cela peut aider quelqu'un d'autre. J'ai commencé par tester le type de chaîne de la variable s, mais pour mon application, il était plus logique de simplement renvoyer s en tant que utf-8. Le processus appelant return_utf sait alors de quoi il traite et peut gérer la chaîne de manière appropriée. Le code n’est pas vierge, mais j’ai l’intention de ne pas utiliser Python version sans test de version ni en importer six. Veuillez commenter avec des améliorations à 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
2
jfl

Vous pouvez utiliser niversal Encoding Detector , mais sachez que cela vous donnera 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 aurez besoin d'obtenir des informations de codage ailleurs, par exemple, le protocole HTTP utilise l'en-tête Content-Type pour cela.

2
Seb

Pour la compatibilité py2/py3, utilisez simplement

import six if isinstance(obj, six.text_type)

0
Vishvajit Pathak