Odpowiedzi:
W Pythonie 3 wszystkie ciągi są ciągami znaków Unicode. Istnieje bytes
typ przechowujący nieprzetworzone bajty.
W Pythonie 2 łańcuch może być typu str
lub typu unicode
. Możesz stwierdzić, który kod używa czegoś takiego:
def whatisthis(s):
if isinstance(s, str):
print "ordinary string"
elif isinstance(s, unicode):
print "unicode string"
else:
print "not a string"
Nie rozróżnia to „Unicode lub ASCII”; rozróżnia tylko typy Pythona. Łańcuch Unicode może składać się wyłącznie z znaków w zakresie ASCII, a bajtowanie może zawierać ASCII, kodowany Unicode, a nawet dane nietekstowe.
Możesz użyć type
lub isinstance
.
W Python 2:
>>> type(u'abc') # Python 2 unicode string literal
<type 'unicode'>
>>> type('abc') # Python 2 byte string literal
<type 'str'>
W Python 2 str
jest tylko sekwencją bajtów. Python nie wie, jakie jest jego kodowanie. Ten unicode
typ jest bezpieczniejszym sposobem przechowywania tekstu. Jeśli chcesz to lepiej zrozumieć, polecam http://farmdev.com/talks/unicode/ .
W Pythonie 3:
>>> type('abc') # Python 3 unicode string literal
<class 'str'>
>>> type(b'abc') # Python 3 byte string literal
<class 'bytes'>
W Pythonie 3 str
jest podobny do Pythona 2 unicode
i służy do przechowywania tekstu. To, co nazywa się str
w Pythonie 2, nazywa się bytes
w Pythonie 3.
Można zadzwonić decode
. Jeśli zgłosi wyjątek UnicodeDecodeError, nie jest prawidłowy.
>>> 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")
czy coś
str(s, "ascii")
W Pythonie 3.x wszystkie ciągi są ciągami znaków Unicode. i wykonanie sprawdzania isinstance dla str (co domyślnie oznacza ciąg Unicode) powinno wystarczyć.
isinstance(x, str)
Jeśli chodzi o Python 2.x, większość osób wydaje się używać instrukcji if, która ma dwa testy. jeden dla str i jeden dla unicode.
Jeśli chcesz sprawdzić, czy masz obiekt „podobny do łańcucha” za pomocą jednej instrukcji, możesz wykonać następujące czynności:
isinstance(x, basestring)
isinstance(u"x",basestring)
zwraca True
.
Unicode nie jest kodowaniem - cytując Kumara McMillana:
Jeśli ASCII, UTF-8 i inne ciągi bajtów są „tekstem” ...
... wtedy Unicode to „tekstowość”;
jest to abstrakcyjna forma tekstu
Przeczytaj Unicode McMillana W Pythonie, całkowicie zdemistalizowanym wykładzie z PyCon 2008, wyjaśnia on rzeczy znacznie lepiej niż większość powiązanych odpowiedzi na temat przepełnienia stosu.
Jeśli twój kod musi być kompatybilny zarówno z Python 2, jak i Python 3, nie możesz bezpośrednio używać rzeczy takich jak isinstance(s,bytes)
lub isinstance(s,unicode)
bez owijania ich w try / try lub w testach wersji Python, ponieważ bytes
jest niezdefiniowany w Pythonie 2 i unicode
niezdefiniowany w Pythonie 3 .
Istnieje kilka brzydkich obejść. Niezwykle brzydkie jest porównywanie nazwy typu zamiast porównywania samego typu. Oto przykład:
# 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)
Prawdopodobnie nieco mniej brzydkim obejściem jest sprawdzenie numeru wersji Pythona, np .:
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)
Oba są niepytoniczne i przez większość czasu jest prawdopodobnie lepszy sposób.
six
, a testy przed six.binary_type
isix.text_type
posługiwać się:
import six
if isinstance(obj, six.text_type)
wewnątrz sześciu bibliotek jest reprezentowany jako:
if PY3:
string_types = str,
else:
string_types = basestring,
if isinstance(obj, six.text_type)
. Ale tak, to imo poprawna odpowiedź.
Zauważ, że w Pythonie 3, niesprawiedliwe jest powiedzenie któregokolwiek z:
str
s są UTFx dla dowolnego x (np. UTF8)
str
s są Unicode
str
s to uporządkowane kolekcje znaków Unicode
Python's str
Typ jest (normalnie) sekwencją punktów kodu Unicode, z których niektóre są mapowane na znaki.
Nawet w Pythonie 3 odpowiedź na to pytanie nie jest tak prosta, jak można sobie wyobrazić.
Oczywistym sposobem przetestowania ciągów zgodnych z ASCII jest próba kodowania:
"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)
Błąd rozróżnia przypadki.
W Pythonie 3 są nawet niektóre ciągi znaków, które zawierają nieprawidłowe punkty kodu Unicode:
"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
Zastosowano tę samą metodę ich rozróżnienia.
To może pomóc komuś innemu. Zacząłem testować typ ciągu zmiennej s, ale dla mojej aplikacji bardziej sensowne było po prostu zwrócenie s jako utf-8. Proces wywołujący return_utf, a następnie wie, z czym ma do czynienia i odpowiednio obsługuje ciąg. Kod nie jest nieskazitelny, ale zamierzam, aby był on niezależny od wersji Pythona bez testu wersji lub importowania sześciu. Skomentuj ulepszenia przykładowego kodu poniżej, aby pomóc innym osobom.
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
Możesz użyć Universal Encoding Detector , ale pamiętaj, że pozwoli ci to odgadnąć, a nie rzeczywiste kodowanie, ponieważ nie można na przykład znać kodowania ciągu „abc”. Będziesz musiał uzyskać informacje o kodowaniu gdzie indziej, np. Protokół HTTP używa do tego nagłówka Content-Type.
Aby uzyskać zgodność z py2 / py3, wystarczy użyć
import six
if isinstance(obj, six.text_type)
Jednym prostym podejściem jest sprawdzenie, czy unicode
jest to funkcja wbudowana. Jeśli tak, jesteś w Pythonie 2, a Twój ciąg znaków będzie ciągiem. Aby upewnić się, że wszystko jest w unicode
porządku, możesz:
import builtins
i = 'cats'
if 'unicode' in dir(builtins): # True in python 2, False in 3
i = unicode(i)