it-swarm-ru.tech

Как проверить, является ли строка юникодом или ascii?

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

241
TIMEX

В 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. Строка Unicode может состоять из чисто символов в диапазоне ASCII, а строка байтов может содержать ASCII, закодированный Unicode или даже нетекстовые данные.

265
Greg Hewgill

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

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

isinstance(x, str)

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

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

isinstance(x, basestring)
43
ThinkBonobo

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

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

... тогда Юникод это "текст-несс";

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

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

31
Alex Dean

Если ваш код должен быть совместим с обе 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)

Они оба не пифоничны, и в большинстве случаев, вероятно, есть лучший способ.

22
Dave Burton

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

import six
if isinstance(obj, six.text_type)

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

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

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

  • strs - это UTFx для любого x (например, UTF8)

  • strs - это Юникод

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

Тип 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

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

4
Veedrac

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

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

2
Seb

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

import six if isinstance(obj, six.text_type)

0
Vishvajit Pathak