Как проверить, является ли строка юникодом или ascii? - PullRequest
246 голосов
/ 14 февраля 2011

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

Ответы [ 10 ]

267 голосов
/ 14 февраля 2011

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

110 голосов
/ 14 февраля 2011

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

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

isinstance(x, str)

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

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

isinstance(x, basestring)
31 голосов
/ 21 мая 2012

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

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

...тогда Unicode - это «text-ness»;

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

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

22 голосов
/ 14 августа 2012

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

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

9 голосов
/ 08 августа 2016

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

import six
if isinstance(obj, six.text_type)

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

if PY3:
    string_types = str,
else:
    string_types = basestring,
4 голосов
/ 09 июля 2014

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

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

  • str s - это Unicode

  • str s - упорядоченные наборы символов Unicode

Python's 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

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

2 голосов
/ 24 декабря 2015

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

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

0 голосов
/ 28 мая 2018

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

import six if isinstance(obj, six.text_type)

...