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

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

10 ответов


в Python 3 все строки являются последовательностями символов Юникода. Есть 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. Строка Юникода может состоять только из символов в диапазоне ASCII, а bytestring может содержать ASCII, кодированный Юникод или даже нетекстовые данные.


просто делать

type(s)

одно скажу unicode, другой скажет str.

вы можете обрабатывать их по отдельности, используя isinstance, например,

if isinstance(s, str):
    print 's is a string object'
elif isinstance(s, unicode):
    print 's is a unicode object'

или вы имеете в виду, что у вас есть str, и вы пытаетесь выяснить, закодирован ли он с помощью ASCII или UTF-8 или что-то еще?

в этом случае попробуйте следующее:

s.decode('ascii')

если возникает исключение, строка не является 100% ASCII.


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

isinstance(x, str)

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

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

isinstance(x, basestring)

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

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

...тогда Юникод - это "text-ness";

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

прочтите Макмиллана Unicode В Python, Полностью Демистифицированный talk от PyCon 2008, это объясняет вещи намного лучше, чем большинство связанных ответов на переполнение стека.


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

это unpythonic, и большую часть времени там, наверное, лучший способ.


использование:

import six
if isinstance(obj, six. text_type)

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

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

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

  • strS-UTFx для любого x (например. В utf8)

  • strs являются Unicode

  • strs-упорядоченные коллекции символов Юникода

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

используется тот же метод, чтобы различать их.


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


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

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

import six if isinstance(obj, six.text_type)