Використання функцій unicode () та encode () у Python


83

У мене проблема з кодуванням змінної шляху та її вставкою до бази даних SQLite . Я намагався вирішити це за допомогою функції encode ("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'>

Нарешті я отримав тип юнікоду , але я все ще маю ту саму помилку, яка була присутня, коли типом змінної шляху був str

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

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

РЕДАГУВАТИ:

Цей оператор execute () викликав помилку:

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

Я забув змінити кодування змінної fullFilePath, яка страждає від тієї ж проблеми, але зараз я дуже заплутався. Чи слід використовувати лише Unicode () або encode ("utf-8"), або обидва?

Я не можу використовувати

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

тому що це викликає цю помилку:

UnicodeDecodeError: кодек 'ascii' не може декодувати байт 0xc5 у положенні 32: порядковий номер не в діапазоні (128)

Версія Python - 2.7.2


де код, який викликає помилку?
newtover

2
Уже відповів на ваш точний питання: [ stackoverflow.com/questions/2392732 / ... [1]: stackoverflow.com/questions/2392732 / ...
garnertb

@newtover Я відредагував запитання.
xralf

Ви перетворили обидві використані змінні на unicode?
newtover

2
Дізнатися, як Python 3 обробляє текст і дані, насправді допомогло мені все зрозуміти. Тоді легко застосувати знання до Python 2.
Олег Припін,

Відповіді:


87

Ви використовуєте 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 - То це вже юнікод? Спробуйте змінити виклик виконання на unicode:cur.execute(u"update docs set path = :fullFilePath where path = :path", locals())
Ендрю Кларк

121

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

Ви декодуєте текст з байтів в Unicode і кодуєте Unicode в байти з деяким кодуванням.

Це є:

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

1
Дуже хороша відповідь, прямо до справи. Я б додав, що це unicodeстосується букв або символів, або більш загально: руни в той час, як strпредставляє байтовий рядок у певному кодуванні, що ви повинні decode(очевидно, у правильному кодуванні), щоб отримати конкретні руни
араїнон

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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.