Was muss ich in Python tun, um herauszufinden, welche Codierung ein String hat?
In Python 3 sind alle Zeichenfolgen Sequenzen von Unicode-Zeichen. Es gibt einen bytes
-Typ, der unformatierte Bytes enthält.
In Python 2 kann ein String vom Typ str
oder vom Typ unicode
sein. Sie können anhand des folgenden Codes feststellen, welcher Code verwendet wird:
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. Ein Unicode-String kann aus reinen Zeichen im Bereich ASCII bestehen, und ein Bytestring kann ASCII, codierten Unicode oder sogar Nicht-Unicode enthalten -textuelle Daten.
Sie können type
oder isinstance
verwenden.
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 ist str
nur eine Folge von Bytes. Python weiß nicht, wie die Kodierung lautet. Die unicode
type 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 ist str
wie Python 2 ist unicode
und wird zum Speichern von Text verwendet genannt str
in Python 2 heißt bytes
in Python 3.
Sie können decode
aufrufen. Wenn es eine UnicodeDecodeError-Ausnahme auslöst, war es 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)
In python 3.x sind alle Strings Sequenzen von Unicode-Zeichen. Es sollte ausreichen, die isinstance-Prüfung für str (was standardmäßig Unicode-String bedeutet) durchzuführen.
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 überprüfen möchten, ob Sie ein "stringartiges" Objekt mit nur einer Anweisung haben, können Sie Folgendes tun:
isinstance(x, basestring)
Unicode ist keine Kodierung - um Kumar McMillan zu zitieren:
Wenn ASCII, UTF-8 und andere Byte-Zeichenfolgen "Text" sind ...
... dann ist Unicode "Text-Ness";
es ist die abstrakte Form des Textes
Lesen Sie McMillans nicode in Python, vollständig entmystifiziert Vortrag von PyCon 2008, in dem die Dinge viel besser erklärt werden als in den meisten verwandten Antworten zu Stack Overflow.
Wenn Ihr Code mit beiden Python 2 und Python 3) kompatibel sein muss, können Sie Dinge wie isinstance(s,bytes)
oder isinstance(s,unicode)
ohne sie entweder in try/except oder in einen python version test zu verpacken, da bytes
undefiniert ist in Python 2 und unicode
sind in Python 3 undefiniert.
Es gibt einige hässliche Problemumgehungen. Eine extrem hässliche Methode besteht darin, 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 ist die Überprüfung der Python Versionsnummer, z. B .:
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.
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,
Beachten Sie, dass es auf Python 3 nicht wirklich fair ist, Folgendes zu sagen:
str
s sind UTFx für jedes x (zB UTF8)
str
s sind Unicode
str
s sind geordnete Sammlungen von Unicode-Zeichen
Der str
-Typ von Python ist (normalerweise) eine Folge von Unicode-Codepunkten, von denen einige Zeichen zuordnen.
Selbst auf 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 angewendet.
Dies mag jemand anderem helfen. Ich habe mit dem Testen des Stringtyps 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, um was es sich handelt, und kann die Zeichenfolge entsprechend behandeln. Der Code ist nicht makellos, aber ich beabsichtige, dass er Python versionagnostisch ist, ohne einen Versionstest durchzuführen oder sechs zu importieren. Bitte kommentieren Sie den folgenden Beispielcode mit Verbesserungen, um anderen Benutzern 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
Sie können niversal Encoding Detector verwenden. Beachten Sie jedoch, dass dies nur die beste Vermutung liefert und 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 den Content-Type-Header dafür.
Für die py2/py3-Kompatibilität verwenden Sie einfach
import six if isinstance(obj, six.text_type)