Wie überprüfe ich, ob eine Zeichenfolge Unicode oder ASCII ist?

271

Was muss ich in Python tun, um herauszufinden, welche Codierung eine Zeichenfolge hat?

TIMEX
quelle
56
Unicode ist keine Codierung.
Ulidtko
Noch wichtiger ist, warum sollte es dich interessieren?
Johnsyweb
@Johnsyweb Wegen{UnicodeDecodeError} 'ascii' codec can't decode byte 0xc2
alex

Antworten:

295

In Python 3 sind alle Zeichenfolgen Sequenzen von Unicode-Zeichen. Es gibt einen bytesTyp, der Rohbytes enthält.

In Python 2 kann eine Zeichenfolge vom Typ stroder vom Typ sein unicode. Mit Code können Sie Folgendes feststellen:

def whatisthis(s):
    if isinstance(s, str):
        print "ordinary string"
    elif isinstance(s, unicode):
        print "unicode string"
    else:
        print "not a string"

Dies unterscheidet nicht zwischen "Unicode oder ASCII". Es werden nur Python-Typen unterschieden. Eine Unicode-Zeichenfolge kann aus reinen Zeichen im ASCII-Bereich bestehen, und ein Bytestring kann ASCII-, codierte Unicode- oder sogar nicht-textuelle Daten enthalten.

Greg Hewgill
quelle
3
@ProsperousHeart: Sie verwenden wahrscheinlich Python 3.
Greg Hewgill
124

Wie man erkennt, ob ein Objekt eine Unicode-Zeichenfolge oder eine Byte-Zeichenfolge ist

Sie können typeoder verwenden isinstance.

In Python 2:

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

In Python 2 strist nur eine Folge von Bytes. Python weiß nicht, wie es codiert ist. Der unicodeTyp ist die sicherere Methode zum Speichern von Text. Wenn Sie dies besser verstehen möchten, empfehle ich http://farmdev.com/talks/unicode/ .

In Python 3:

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

In Python 3 strist es wie in Python 2 unicodeund wird zum Speichern von Text verwendet. Was strin Python 2 genannt wurde, heißt bytesin Python 3.


Wie man erkennt, ob eine Byte-Zeichenfolge gültig ist utf-8 oder ascii

Sie können anrufen decode. Wenn eine UnicodeDecodeError-Ausnahme ausgelöst wird, war sie nicht gültig.

>>> 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)
Mikel
quelle
Nur als Referenz für andere Leute - str.decode existiert nicht in Python 3. Sieht aus wie Sie müssen unicode(s, "ascii")oder so
Shadow
3
Entschuldigung, ich meintestr(s, "ascii")
Shadow
1
Dies ist nicht genau für Python 3
ProsperousHeart
2
@ProsperousHeart Aktualisiert, um Python 3 abzudecken. Und um zu versuchen, den Unterschied zwischen Bytestrings und Unicode-Strings zu erklären.
Mikel
44

In Python 3.x sind alle Zeichenfolgen Sequenzen von Unicode-Zeichen. und die isinstance-Prüfung für str (was standardmäßig Unicode-String bedeutet) sollte ausreichen.

isinstance(x, str)

In Bezug auf Python 2.x scheinen die meisten Leute eine if-Anweisung zu verwenden, die zwei Prüfungen enthält. eine für str und eine für unicode.

Wenn Sie jedoch überprüfen möchten, ob Sie ein 'stringartiges' Objekt mit einer einzigen Anweisung haben, können Sie Folgendes tun:

isinstance(x, basestring)
ThinkBonobo
quelle
Das ist falsch. In Python 2.7 isinstance(u"x",basestring)kehrt zurück True.
PythonNut
11
@ PythonNut: Ich glaube, das war der Punkt. Die Verwendung von isinstance (x, basestring) reicht aus, um die oben genannten unterschiedlichen Doppeltests zu ersetzen.
KQ.
5
Es ist in vielen Fällen nützlich, aber offensichtlich nicht das, was der Fragesteller meinte.
Mhsmith
3
Dies ist die Antwort auf die Frage. Alle anderen haben das, was OP gesagt hat, falsch verstanden und allgemeine Antworten zur Typprüfung in Python gegeben.
Fiatjaf
1
Beantwortet die Frage von OP nicht. Der Titel der Frage (allein) KANN so interpretiert werden, dass diese Antwort richtig ist. OP sagt jedoch in der Beschreibung der Frage ausdrücklich "finde heraus, welche", und diese Antwort spricht das nicht an.
MD004
31

Unicode ist keine Kodierung - um Kumar McMillan zu zitieren:

Wenn ASCII, UTF-8 und andere Byte-Zeichenfolgen "Text" sind ...

... dann ist Unicode "Text";

es ist die abstrakte Form von Text

Lesen Sie McMillans Unicode In Python, einem vollständig entmystifizierten Vortrag von PyCon 2008, der die Dinge viel besser erklärt als die meisten verwandten Antworten zu Stack Overflow.

Alex Dean
quelle
Diese Folien sind wahrscheinlich die beste Einführung in Unicode, die mir bisher begegnet ist
Jonny,
23

Wenn Ihr Code sowohl mit Python 2 als auch mit Python 3 kompatibel sein muss , können Sie Dinge wie isinstance(s,bytes)oder isinstance(s,unicode)ohne Umbruch weder in try / exception noch in einem Python-Versionstest direkt verwenden , da er bytesin Python 2 unicodeundefiniert und in Python 3 undefiniert ist .

Es gibt einige hässliche Problemumgehungen. Sehr hässlich ist es, den Namen des Typs zu vergleichen , anstatt den Typ selbst zu vergleichen. Hier ist ein Beispiel:

# 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)

Eine wohl etwas weniger hässliche Problemumgehung besteht darin, die Python-Versionsnummer zu überprüfen, z.

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)

Diese sind beide unpythonisch und die meiste Zeit gibt es wahrscheinlich einen besseren Weg.

Dave Burton
quelle
6
Der bessere Weg ist wahrscheinlich zu verwenden sixund gegen six.binary_typeundsix.text_type
Ian Clelland
1
Sie können Typ (en) .__ name__ verwenden , um Typnamen zu prüfen .
Paulo Freitas
Ich bin mir des Anwendungsfalls für dieses Codebit nicht ganz sicher, es sei denn, es liegt ein logischer Fehler vor. Ich denke, der Python 2-Code sollte ein "Nicht" enthalten. Ansonsten konvertieren Sie alles in Unicode-Strings für Python 3 und das Gegenteil für Python 2!
Oligofren
Ja, Oligofren, das ist es, was es tut. Die internen Standardzeichenfolgen sind Unicode in Python 3 und ASCII in Python 2. Die Codefragmente konvertieren also Text in den internen Standardzeichenfolgentyp (sei es Unicode oder ASCII).
Dave Burton
12

verwenden:

import six
if isinstance(obj, six.text_type)

Innerhalb der sechs Bibliotheken wird es dargestellt als:

if PY3:
    string_types = str,
else:
    string_types = basestring,
Madjardi
quelle
2
es sollte sein if isinstance(obj, six.text_type) . Aber ja das ist imo die richtige Antwort.
Karantan
Beantwortet die Frage von OP nicht. Der Titel der Frage (allein) KANN so interpretiert werden, dass diese Antwort richtig ist. OP sagt jedoch in der Beschreibung der Frage ausdrücklich "finde heraus, welche", und diese Antwort spricht das nicht an.
MD004
4

Beachten Sie, dass es in Python 3 nicht fair ist, Folgendes zu sagen:

  • strs sind UTFx für jedes x (z. B. UTF8)

  • strs sind Unicode

  • strs sind geordnete Sammlungen von Unicode-Zeichen

Pythons strTyp ist (normalerweise) eine Folge von Unicode-Codepunkten, von denen einige Zeichen zugeordnet sind.


Selbst unter Python 3 ist es nicht so einfach, diese Frage zu beantworten, wie Sie sich vorstellen können.

Ein offensichtlicher Weg, um auf ASCII-kompatible Zeichenfolgen zu testen, ist ein Codierungsversuch:

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

Der Fehler unterscheidet die Fälle.

In Python 3 gibt es sogar einige Zeichenfolgen, die ungültige Unicode-Codepunkte enthalten:

"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

Die gleiche Methode zur Unterscheidung wird verwendet.

Veedrac
quelle
3

Dies kann jemand anderem helfen. Ich habe mit dem Testen des Zeichenfolgentyps der Variablen s begonnen, aber für meine Anwendung war es sinnvoller, s einfach als utf-8 zurückzugeben. Der Prozess, der return_utf aufruft, weiß dann, womit er es zu tun hat, und kann die Zeichenfolge entsprechend behandeln. Der Code ist nicht makellos, aber ich beabsichtige, dass er Python-Versionsunabhängig ist, ohne dass ein Versionstest durchgeführt oder sechs importiert werden. Bitte kommentieren Sie den folgenden Beispielcode mit Verbesserungen, um anderen Personen zu helfen.

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
jfl
quelle
Du mein Freund hast es verdient, die richtige Antwort zu sein! Ich benutze Python 3 und hatte immer noch Probleme, bis ich diesen Schatz gefunden habe!
Mnnsr
2

Sie könnten den Universal Encoding Detector verwenden , aber beachten Sie, dass er Ihnen nur die bestmögliche Vermutung gibt, nicht die tatsächliche Codierung, da es beispielsweise unmöglich ist, die Codierung eines Strings "abc" zu kennen. Sie müssen Codierungsinformationen an anderer Stelle abrufen, z. B. verwendet das HTTP-Protokoll dafür den Content-Type-Header.

Seb
quelle
0

Für py2 / py3-Kompatibilität einfach verwenden

import six if isinstance(obj, six.text_type)

Vishvajit Pathak
quelle
0

Ein einfacher Ansatz besteht darin, zu überprüfen, ob unicodees sich um eine integrierte Funktion handelt. Wenn ja, befinden Sie sich in Python 2 und Ihre Zeichenfolge ist eine Zeichenfolge. Um sicherzustellen, dass alles in unicodeeinem ist, kann man:

import builtins

i = 'cats'
if 'unicode' in dir(builtins):     # True in python 2, False in 3
  i = unicode(i)
duhaime
quelle