Як перевірити, чи є рядок unicode чи ascii?


271

Що мені робити в Python, щоб зрозуміти, яке кодування має рядок?


56
Unicode не є кодуванням.
ulidtko

Що ще важливіше, навіщо вам турбуватися?
Johnsyweb

@Johnsyweb Через{UnicodeDecodeError} 'ascii' codec can't decode byte 0xc2
alex

Відповіді:


295

У 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 або навіть нетекстові дані.


3
@ProsperousHeart: Ви, мабуть, використовуєте Python 3.
Грег Х'югілл

124

Як визначити, чи об'єкт - це рядок 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.


Як сказати, чи є байт-рядок дійсним utf-8 або ascii

Можна зателефонувати 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)

Тільки для довідки інших людей - str.decode не існує в python 3. Схоже, вам потрібно unicode(s, "ascii")чи щось
Shadow

3
Вибачте, я мав на увазіstr(s, "ascii")
Тінь

1
Це не точно для python 3
ProsperousHeart

2
@ProsperousHeart Оновлено, щоб охопити Python 3. І спробувати пояснити різницю між байст-веснянками та рядками Unicode.
Мікель

44

У python 3.x всі рядки - це послідовності символів Unicode. і перевірка isin substance для str (а це означає, що за замовчуванням є рядок unicode).

isinstance(x, str)

Що стосується python 2.x, то, здається, більшість людей використовують оператор if, який має дві перевірки. один для str і один для unicode.

Якщо ви хочете перевірити, чи є у вас об'єкт "схожий на рядок", все з одним твердженням, ви можете зробити наступне:

isinstance(x, basestring)

Це помилково. У Python 2.7 isinstance(u"x",basestring)повертається True.
PythonNut

11
@PythonNut: Я вважаю, що це було справа. Використання речовини (x, basestring) достатньо для заміни вищезгаданих подвійних тестів.
KQ.

5
Це корисно у багатьох випадках, але очевидно не те, що мав на увазі запитуючий.
mhsmith

3
Це відповідь на запитання. Всі інші неправильно зрозуміли, що сказав ОП, і дали загальні відповіді щодо перевірки типу в Python.
фіатжаф

1
Не відповідає на питання ОП. Заголовок питання (поодинці) ДУЖЕ трактуватися таким чином, щоб ця відповідь була правильною. Однак, ОП спеціально говорить "зрозуміти, що" в описі питання, і ця відповідь не відповідає на це.
MD004

31

Unicode не є кодуванням - щоб процитувати Кумара Макміллана:

Якщо ASCII, UTF-8 та інші байтові рядки є "текстовими" ...

... тоді Unicode є "текстовою";

це абстрактна форма тексту

Прочитайте Unicode McMillan в Python, повністю демістифіковані розмови з PyCon 2008, це пояснює речі набагато краще, ніж більшість відповідних відповідей на переповнення стека.


Ці слайди - це, мабуть, найкраще знайомство з Unicode, з яким я натрапив на сьогодні
Jonny

23

Якщо ваш код повинен бути сумісним як з 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)

Вони обидва непітонічні, і більшість часу, мабуть, є кращий спосіб.


6
Кращий спосіб - це, мабуть, використання sixта тестування проти six.binary_typeтаsix.text_type
Ian Clelland

1
Ви можете використовувати типи (и) .__ name__ для імен типів зонду.
Пауло Фрейтас

Я не зовсім впевнений у випадку використання цього біта коду, якщо не є логічної помилки. Я думаю, що в коді python 2 повинно бути "не". Інакше ви перетворите все в рядки unicode для Python 3 і навпаки для Python 2!
олігофрен

Так, олігофрен, це і робиться. Стандартними внутрішніми рядками є Unicode в Python 3 та ASCII в Python 2. Отже, фрагменти коду перетворюють текст у стандартний внутрішній тип рядка (будь то Unicode або ASCII).
Дейв Бертон

12

використання:

import six
if isinstance(obj, six.text_type)

всередині шести бібліотек вона представлена ​​як:

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

2
так і має бути if isinstance(obj, six.text_type) . Але так, це є правильною відповіддю.
Карантан

Не відповідає на питання ОП. Заголовок питання (поодинці) ДУЖЕ трактуватися таким чином, щоб ця відповідь була правильною. Однак, ОП спеціально говорить "зрозуміти, що" в описі питання, і ця відповідь не відповідає на це.
MD004

4

Зауважте, що на Python 3 не дуже чесно сказати будь-яке:

  • strs - UTFx для будь-якого x (наприклад, UTF8)

  • strs - Unicode

  • strs упорядковані колекції символів 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

Використовується той же метод їх розрізнення.


3

Це може допомогти комусь іншому, я розпочав тестування на тип рядка змінної 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

Ви, мій друг, заслуговуєте на правильну відповідь! Я використовую python 3, і я все ще мав проблеми, поки не знайшов цей скарб!
mnsr

2

Ви можете використовувати універсальний детектор кодування , але пам’ятайте, що він просто дасть вам найкращі здогадки, а не власне кодування, оскільки неможливо, наприклад, знати кодування рядка «abc». Інформацію про кодування вам потрібно буде отримати в іншому місці, наприклад, протокол HTTP використовує для цього заголовок Content-Type.



0

Один простий підхід - перевірити, чи unicodeє вбудована функція. Якщо так, ви перебуваєте в Python 2, і ваша рядок буде рядком. Щоб усе було в unicodeодному, можна зробити:

import builtins

i = 'cats'
if 'unicode' in dir(builtins):     # True in python 2, False in 3
  i = unicode(i)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.