Использование функций unicode () и encode () в Python

83

У меня проблема с кодированием переменной пути и ее вставкой в базу данных SQLite . Я попытался решить эту проблему с помощью функции кодирования ("utf-8"), которая не помогла. Затем я использовал функцию unicode (), которая дает мне тип unicode .

print type(path)                  # <type 'unicode'>
path = path.replace("one", "two") # <type 'str'>
path = path.encode("utf-8")       # <type 'str'> strange
path = unicode(path)              # <type 'unicode'>

Наконец, я получил тип Unicode , но у меня все еще есть та же ошибка, которая присутствовала, когда тип переменной пути был str

sqlite3.ProgrammingError: нельзя использовать 8-битные строки байтов, если вы не используете text_factory, которая может интерпретировать 8-битные строки байтов (например, text_factory = str). Вместо этого настоятельно рекомендуется просто переключить приложение на строки Unicode.

Не могли бы вы помочь мне решить эту ошибку и объяснить, как правильно использовать encode("utf-8")и unicode()функции? Я часто с этим борюсь.

РЕДАКТИРОВАТЬ:

Этот оператор execute () вызвал ошибку:

cur.execute("update docs set path = :fullFilePath where path = :path", locals())

Я забыл изменить кодировку переменной fullFilePath, которая страдает той же проблемой, но сейчас я очень запутался. Должен ли я использовать только unicode () или кодировать ("utf-8") или оба?

Я не могу использовать

fullFilePath = unicode(fullFilePath.encode("utf-8"))

потому что это вызывает эту ошибку:

UnicodeDecodeError: кодек ascii не может декодировать байт 0xc5 в позиции 32: порядковый номер не в диапазоне (128)

Версия Python 2.7.2

xralf
источник
где код, вызывающий ошибку?
newtover
2
На ваш точный вопрос уже был дан ответ: [ stackoverflow.com/questions/2392732/… [1]: stackoverflow.com/questions/2392732/…
garnertb
@newtover Редактировал вопрос.
xralf
вы преобразовали обе используемые переменные в unicode?
newtover
2
Изучение того, как Python 3 обрабатывает текст и данные, действительно помогло мне все понять. Тогда легко применить полученные знания к Python 2.
Олег Припин

Ответы:

88

Вы encode("utf-8")неправильно используете . Строки байтов Python ( strтип) имеют кодировку, а Unicode - нет. Вы можете преобразовать строку Unicode в строку байтов Python, используя uni.encode(encoding), и вы можете преобразовать строку байтов в строку Unicode, используя s.decode(encoding)(или эквивалентно unicode(s, encoding)).

Если fullFilePathи pathв настоящее время являются strтипом, вам следует выяснить, как они закодированы. Например, если текущая кодировка - utf-8, вы должны использовать:

path = path.decode('utf-8')
fullFilePath = fullFilePath.decode('utf-8')

Если это не поможет, проблема может заключаться в том, что вы не используете строку Unicode в своем execute()вызове, попробуйте изменить ее на следующее:

cur.execute(u"update docs set path = :fullFilePath where path = :path", locals())
Эндрю Кларк
источник
Это утверждение по- fullFilePath = fullFilePath.decode("utf-8")прежнему вызывает ошибку UnicodeEncodeError: 'ascii' codec can't encode characters in position 32-34: ordinal not in range(128). fullFilePath - это комбинация типа str и строки, взятой из текстового столбца таблицы db, которая должна быть в кодировке utf-8.
xralf
В соответствии с этим, но это может быть UTF-8, UTF-16BE или UTF-16LE. Могу я как-нибудь это узнать?
xralf
@xralf, если вы комбинируете разные strобъекты, возможно, вы смешиваете кодировки. Можешь показать результат print repr(fullFilePath)?
Эндрю Кларк
Я могу показать это только перед вызовом decode () . Проблемные символы: \ u0161 и \ u0165.
xralf
@xralf - Так это уже юникод? Попробуйте изменить вызов execute на unicode:cur.execute(u"update docs set path = :fullFilePath where path = :path", locals())
Эндрю Кларк,
122

strтекстовое представление в байтах, unicodeтекстовое представление в символах.

Вы декодируете текст из байтов в юникод и кодируете юникод в байты с некоторой кодировкой.

То есть:

>>> 'abc'.decode('utf-8')  # str to unicode
u'abc'
>>> u'abc'.encode('utf-8') # unicode to str
'abc'

UPD сентябрь 2020 : ответ был написан, когда в основном использовался Python 2. В Python 3, strбыл переименован в bytes, и unicodeбыл переименован в str.

>>> b'abc'.decode('utf-8') # bytes to str
'abc'
>>> 'abc'.encode('utf-8'). # str to bytes
b'abc'
новый
источник
1
Очень хороший ответ, прямо по делу. Я бы добавил, что unicodeречь идет о буквах или символах, или в более общем смысле: руны, в то время как strпредставляют собой строку байтов в определенной кодировке, которую вы должны decode(очевидно, в правильной кодировке) получить определенные руны
arainone
1
Python 3.8 >>'str' object has no attribute 'decode'
Йохан Обадия
у вас есть документация по замене Unicode на str? Я не могу найти
cikatomo
1
@cikatomo Это одно из ключевых изменений в Python 3: docs.python.org/3.0/whatsnew/…
newtover
1

Убедитесь, что вы установили настройки локали прямо перед запуском скрипта из оболочки, например

$ locale -a | grep "^en_.\+UTF-8"
en_GB.UTF-8
en_US.UTF-8
$ export LC_ALL=en_GB.UTF-8
$ export LANG=en_GB.UTF-8

Документы: man locale, man setlocale.

Kenorb
источник