Расшифровка, если это не Unicode - PullRequest
13 голосов
/ 04 октября 2010

Я хочу, чтобы моя функция принимала аргумент, который может быть объектом Unicode или строкой в ​​кодировке utf-8.Внутри моей функции я хочу преобразовать аргумент в юникод.У меня что-то вроде этого:

def myfunction(text):
    if not isinstance(text, unicode):
        text = unicode(text, 'utf-8')

    ...

Можно ли избежать использования isinstance?Я искал что-то более дружественное к наборам уток.

Во время моих экспериментов с декодированием я столкнулся с несколькими странными поведениями Python.Например:

>>> u'hello'.decode('utf-8')
u'hello'
>>> u'cer\xf3n'.decode('utf-8')
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/usr/lib/python2.6/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf3' in po
sition 3: ordinal not in range(128)

Или

>>> u'hello'.decode('utf-8')
u'hello' 12:11
>>> unicode(u'hello', 'utf-8')
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: decoding Unicode is not supported

Кстати.Я использую Python 2.6

Ответы [ 2 ]

18 голосов
/ 04 октября 2010

Вы можете просто попытаться декодировать его с помощью кодека 'utf-8', а если это не сработает, вернуть объект.

def myfunction(text):
    try:
        text = unicode(text, 'utf-8')
    except TypeError:
        return text

print(myfunction(u'cer\xf3n'))
# cerón

Когда вы берете объект Unicode и вызываете его decode Метод с кодеком 'utf-8', Python сначала пытается преобразовать объект Unicode в строковый объект, а затем вызывает метод декодирования ('utf-8') объекта строки.

Иногда преобразование из Unicodeобъект в строку объект терпит неудачу, потому что Python2 по умолчанию использует кодек ascii.

Поэтому, как правило, никогда не пытайтесь декодировать объекты Unicode.Или, если вам нужно попробовать, поместите его в блок try..except.Может быть несколько кодеков, для которых декодирование объектов Unicode работает в Python2 (см. Ниже), но они были удалены в Python3.

См. Этот билет ошибки Python для интересного обсуждениявыпуск, а также блог Гвидо ван Россума :

«Мы применяем немного другой подход к кодекам: в то время как в Python 2 кодеки могут принимать Unicode или 8-битные каквведите и выведите либо в качестве вывода, в Py3k, кодировка - это всегда перевод строки Unicode (текстовой) в массив байтов, а декодирование всегда идет в обратном направлении. Это означает, что нам пришлось отброситьнесколько кодеков, которые не вписываются в эту модель, например rot13, base64 и bz2 (эти преобразования все еще поддерживаются, только через API кодирования / декодирования). "

0 голосов
/ 04 октября 2010

Я не знаю ни одного хорошего способа избежать проверки isinstance в вашей функции, но, возможно, кто-то еще будет. Я могу отметить, что две странности, на которые вы ссылаетесь, заключаются в том, что вы делаете что-то, что не имеет смысла: пытаетесь декодировать в Unicode то, что уже декодировано в Unicode.

Первый вместо этого должен выглядеть следующим образом, который декодирует кодировку UTF-8 этой строки в версию Unicode:

>>> 'cer\xc3\xb3n'.decode('utf-8')
u'cer\xf3n'

И ваш второй должен выглядеть следующим образом (без использования u'' строкового литерала Unicode):

>>> unicode('hello', 'utf-8')
u'hello'
...