Відповіді:
У Python 3 всі рядки - це послідовності символів Unicode. Існує bytes
тип, який містить сирі байти.
У Python 2 рядок може бути типу str
або типу unicode
. Ви можете сказати, за допомогою коду щось подібне:
def whatisthis(s):
if isinstance(s, str):
print "ordinary string"
elif isinstance(s, unicode):
print "unicode string"
else:
print "not a string"
Це не відрізняє "Unicode або ASCII"; він розрізняє лише типи Python. Рядок Unicode може складатися з символів, що знаходяться в діапазоні ASCII, а атестація може містити ASCII, закодований Unicode або навіть нетекстові дані.
Ви можете використовувати type
або isinstance
.
У Python 2:
>>> type(u'abc') # Python 2 unicode string literal
<type 'unicode'>
>>> type('abc') # Python 2 byte string literal
<type 'str'>
У Python 2 - str
це лише послідовність байтів. Python не знає, що таке кодування. unicode
Типу є більш безпечним способом для зберігання тексту. Якщо ви хочете зрозуміти це більше, рекомендую http://farmdev.com/talks/unicode/ .
У Python 3:
>>> type('abc') # Python 3 unicode string literal
<class 'str'>
>>> type(b'abc') # Python 3 byte string literal
<class 'bytes'>
У Python 3 str
схожий на Python 2 unicode
, і використовується для зберігання тексту. Те, що називалося str
в Python 2, називається bytes
в Python 3.
Можна зателефонувати decode
. Якщо він викликає виключення UnicodeDecodeError, він не був дійсним.
>>> 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")
чи щось
str(s, "ascii")
У python 3.x всі рядки - це послідовності символів Unicode. і перевірка isin substance для str (а це означає, що за замовчуванням є рядок unicode).
isinstance(x, str)
Що стосується python 2.x, то, здається, більшість людей використовують оператор if, який має дві перевірки. один для str і один для unicode.
Якщо ви хочете перевірити, чи є у вас об'єкт "схожий на рядок", все з одним твердженням, ви можете зробити наступне:
isinstance(x, basestring)
isinstance(u"x",basestring)
повертається True
.
Unicode не є кодуванням - щоб процитувати Кумара Макміллана:
Якщо ASCII, UTF-8 та інші байтові рядки є "текстовими" ...
... тоді Unicode є "текстовою";
це абстрактна форма тексту
Прочитайте Unicode McMillan в Python, повністю демістифіковані розмови з PyCon 2008, це пояснює речі набагато краще, ніж більшість відповідних відповідей на переповнення стека.
Якщо ваш код повинен бути сумісним як з Python 2, так і з Python 3, ви не можете безпосередньо використовувати такі речі, як isinstance(s,bytes)
або isinstance(s,unicode)
без їх загортання, ні в спробі / за винятком, ні в тесті версії python, оскільки bytes
це не визначено в Python 2 і unicode
не визначено в Python 3 .
Є деякі потворні обходи. Надзвичайно негарно - порівнювати назву типу, а не порівнювати сам тип. Ось приклад:
# 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)
Можливо, трохи менш негарним способом є перевірка номера версії Python, наприклад:
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)
Вони обидва непітонічні, і більшість часу, мабуть, є кращий спосіб.
six
та тестування проти six.binary_type
таsix.text_type
використання:
import six
if isinstance(obj, six.text_type)
всередині шести бібліотек вона представлена як:
if PY3:
string_types = str,
else:
string_types = basestring,
if isinstance(obj, six.text_type)
. Але так, це є правильною відповіддю.
Зауважте, що на Python 3 не дуже чесно сказати будь-яке:
str
s - UTFx для будь-якого x (наприклад, UTF8)
str
s - Unicode
str
s упорядковані колекції символів Unicode
str
Тип Python - це (як правило) послідовність точок коду Unicode, деякі з яких позначаються символами.
Навіть на Python 3 відповісти на це питання не так просто, як ви могли собі уявити.
Очевидним способом перевірити рядки, сумісні з ASCII, є спроба кодування:
"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)
Помилка відрізняє випадки.
У Python 3 є навіть деякі рядки, які містять недійсні точки коду 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
Використовується той же метод їх розрізнення.
Це може допомогти комусь іншому, я розпочав тестування на тип рядка змінної s, але для мого додатка було більше сенсу просто повернути s як utf-8. Процес, що викликає return_utf, знає, з чим він має справу, і може обробляти рядок належним чином. Код не є первозданним, але я маю намір бути агностиком Python версії без тестової версії або імпорту шести. Будь ласка, коментуйте вдосконалення зразка коду нижче, щоб допомогти іншим.
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
Ви можете використовувати універсальний детектор кодування , але пам’ятайте, що він просто дасть вам найкращі здогадки, а не власне кодування, оскільки неможливо, наприклад, знати кодування рядка «abc». Інформацію про кодування вам потрібно буде отримати в іншому місці, наприклад, протокол HTTP використовує для цього заголовок Content-Type.
Для сумісності py2 / py3 просто використовуйте
import six
if isinstance(obj, six.text_type)