Как проверить, является ли строка unicode или ascii?

Что мне нужно сделать в Python, чтобы выяснить, какая кодировка строки?

Ответ 1

В 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 или даже нетекстовые данные.

Ответ 2

Как определить, является ли объект строкой 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)

Ответ 3

В python 3.x все строки являются последовательностями символов Unicode. и выполнение проверки isinstance для str (что означает строку unicode по умолчанию) должно быть достаточным.

isinstance(x, str)

Что касается python 2.x, Большинство людей, похоже, используют оператор if, который имеет две проверки. один для str и один для юникода.

Если вы хотите проверить, есть ли у вас объект "string-like" все с одним выражением, вы можете сделать следующее:

isinstance(x, basestring)

Ответ 4

Unicode не является кодировкой - цитирует Кумара Макмиллана:

Если ASCII, UTF-8 и другие строки байтов являются "текстом"...

... тогда Unicode является "text-ness";

это абстрактная форма текста

Прочитайте McMillan Unicode In Python, полностью демистифицированный из PyCon 2008, он объясняет многое намного лучше, чем большинство связанных ответов на Stack Overflow.

Ответ 5

Если ваш код должен быть совместим с и Python 2 и Python 3, вы не можете напрямую использовать такие вещи, как isinstance(s,bytes) или isinstance(s,unicode), не обертывая их в try/except или python version test, потому что bytes есть undefined в Python 2 и unicode есть undefined в 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

использовать:

import six
if isinstance(obj, six.text_type)

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

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

Ответ 7

Обратите внимание, что на Python 3 это не очень справедливо сказать:

  • str являются UTFx для любого x (например, UTF8)

  • str являются Unicode

  • str - упорядоченные коллекции символов Unicode

Тип Python str - это (как правило) последовательность кодовых точек 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

Используется тот же метод для их отличия.

Ответ 8

Вы можете использовать Универсальный детектор кодирования, но имейте в виду, что он просто даст вам лучшее предположение, а не фактическую кодировку, поскольку невозможно знать кодировку строки "abc", например. Вам нужно будет получить информацию о кодировании в другом месте, например, HTTP-протокол использует заголовок Content-Type для этого.

Ответ 9

Это может помочь кому-то еще, я начал тестировать строковый тип переменной 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

Ответ 10

Для совместимости с py2/py3 просто используйте

import six if isinstance(obj, six.text_type)

Ответ 11

Один простой подход - проверить, является ли unicode встроенной функцией. Если это так, вы находитесь в Python 2, и ваша строка будет строкой. Чтобы убедиться, что все в unicode можно сделать:

import builtins

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