Home

Tags

Кодировки в python

2010-03-27 python кодировки

прочтение статьи занимает 4мин, с обдумыванием - 10мин :)
примечание: данная статья относится к python 2.x, но для python 3.x принцип тот же

Общее

В python есть 2 объекта работающими с текстом: unicode и str, объект unicode хранит символы в формате (кодировке) unicode, объект str является набором байт/символов в которых python хранит остальные кодировки (utf8, cp1251, cp866, koi8-r и др).

Кодировку unicode можно считать рабочей кодировкой питона т.к. она предназначена для её использования в самом скрипте - для разных операций над строками.
Внешняя кодировка (объект str) предназначена для хранения и передачи текстовой информации вне скрипта, например для сохранения в файл или передачи по сети. Поэтому в данной статье я её назвал внешней. Самой используемой кодировкой в мире является utf8 и число приложений переходящих на эту кодировку растет каждый день, таким образом превращаясь в "стандарт". Эта кодировка хороша тем что для хранения текста она занимает оптимальное кол-во памяти и с помощью её можно закодировать почти все языки мира ( в отличие от cp1251 и подобных однобайтовых кодировок). Поэтому рекомендуется везде использовать utf8, и при написании скриптов.

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

Скрипт питона, в самом начале скрипта указываем кодировку файла и сохраняем в ней файл
# coding: utf8
либо
# -*- coding: utf-8 -*- 
для того что-бы интерпретатор python понял в какой кодировке файл


Строки в скрипте
Строки в скрипте хранятся байтами, от кавычки до кавычки:
print 'Привет'
= 6 байт при cp1251
= 12 байт при utf8

Если перед строкой добавить символ u, то при запуске скрипта, эта байтовая строка будет декодирована в unicode из кодировки указанной в начале:
# coding:utf8
print u'Привет'
и если кодировка содержимого в файле отличается от указанной, то в строке могут быть "битые символы"


Загрузка и сохранение файла
# coding: utf8

# Загружаем файл с кодировкай utf8
text = open('file.txt','r').read()

# Декодируем из utf8 в unicode - из внешней в рабочую
text = text.decode('utf8')

# Работаем с текстом
text += text

# Кодируем тест из unicode в utf8 - из рабочей во внешнюю
text = text.encode('utf8')

# Сохраняем в файл с кодировкий utf8
open('file.txt','w').write(text)


Текст в скрипте
# coding: utf8

a = 'Текст в utf8'
b = u'Текст в unicode'
# Эквивалентно: b = 'Текст в unicode'.decode('utf8')
# т.к. сам скрипт хранится в utf8

print 'a =',type(a),a
# декодируем из utf-8 в unicode и далее unicode в cp866 (кодировка консоли winXP ru)
print 'a2 =',type(a),a.decode('utf8').encode('cp866')
print 'b =',type(b),b
Процедуре print текст желательно передавать в рабочей кодировке либо кодировать в кодировку ОС.
Результат скрипта при запуске из консоли windows XP:
a = <type 'str'> ╨в╨╡╨║╤Б╤В ╨▓ utf8
a2 = <type 'str'> Текст в utf8
b = <type 'unicode'> Текст в unicode
В последней строке print преобразовал unicode в cp866 автоматический, см. следующий пункт


Авто-преобразование кодировки
В некоторых случаях для упрощения разработки python делает преобразование кодировки, пример с методом print можно посмотреть в предыдущем пункте.
В примере ниже, python сам переводит utf8 в unicode - приводит к одной кодировке для того что-бы сложить строки.
# coding: utf8

# Устанавливаем стандартную внешнюю кодировку = utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')

a = 'Текст в utf8'
b = u'Текст в unicode'
c = a + b

print 'a =',type(a),a
print 'b =',type(b),b
print 'c =',type(c),c
Результат
a = <type 'str'> Текст в utf8
b = <type 'unicode'> Текст в unicode
c = <type 'unicode'> Текст в utf8Текст в unicode
Как видим результирующая строка "c" в unicode. Если бы кодировки строк совпадали то авто-перекодирования не произошло бы и результирующая строка содержала кодировку слагаемых строк.
Авто-перекодирование обычно срабатывает когда происходит взаимодействие разных кодировок.


Пример авто-преобразования кодировок в сравнении
# coding: utf8

# Устанавливаем стандартную внешнюю кодировку = utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')

print '1. utf8 and unicode', 'true' if u'Слово'.encode('utf8') == u'Слово' else 'false'
print '2. utf8 and cp1251', 'true' if u'Слово'.encode('utf8') == u'Слово'.encode('cp1251') else 'false'
print '3. cp1251 and unicode', 'true' if u'Слово'.encode('cp1251') == u'Слово' else 'false'

Результат
1. utf8 and unicode true
2. utf8 and cp1251 false
script.py:10: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
  print '3. cp1251 and unicode', 'true' if u'Слово'.encode('cp1251') == u'Слово' else 'false'
3. cp1251 and unicode false
В сравнении 1, кодировка utf8 преобразовалась в unicode и сравнение произошло корректно.
В сравнении 2, сравниваются кодировки одного вида - обе внешние, т.к. кодированы они в разных кодировках условие выдало что они не равны.
В сравнении 3, выпало предупреждение из за того что выполняется сравнение кодировок разного вида - рабочая и внешняя, а авто-декодирование не произошло т.к. стандартная внешняя кодировка = utf8, и декодировать строку в кодировке cp1251 методом utf8 питон не смог.


Вывод списков
# coding: utf8

d = ['Тест','списка']

print '1',d
print '2',d.__repr__()
print '3',','.join(d)
Результат:
1 ['\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82', '\xd1\x81\xd0\xbf\xd0\xb8\xd1\x81\xd0\xba\xd0\xb0']
2 ['\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82', '\xd1\x81\xd0\xbf\xd0\xb8\xd1\x81\xd0\xba\xd0\xb0']
3 Тест,списка
При выводе списка, происходит вызов [{repr}]() который возвращает внутреннее представление этого спиcка - print 1 и 2 являются аналогичными. Для корректного вывода списка, его нужно преобразовать в строку - print 3.

Установка внешней кодировки при запуске
PYTHONIOENCODING=utf8 python 1.py



статья будет дополняться...