Найти - Пользователи
Полная версия: проблема кодировок в pythone 2.6 глазами не профессионала
Начало » Python для новичков » проблема кодировок в pythone 2.6 глазами не профессионала
1
beliy_shum
я учусь писать прогараммы на питоне и вот мне пришлось использовать питон 2.6 а не 3.0 т.к. многие библиотеки ещё не пересобраны.
Как и следовало ожидать, я столкнулся с проблемой кодировок.

в 2.6:
# -*- coding: utf-8 -*-
>>> list1 = ["этот", "тот", ["он", "другой"]]
>>> list2 = ['пока', 'привет']
>>> list1
['\xd1\x8d\xd1\x82\xd0\xbe\xd1\x82', '\xd1\x82\xd0\xbe\xd1\x82', ['\xd0\xbe\xd0\xbd', '\xd0\xb4\xd1\x80\xd1\x83\xd0\xb3\xd0\xbe\xd0\xb9']]
>>> list2
['\xd0\xbf\xd0\xbe\xd0\xba\xd0\xb0', '\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82']
>>> print list1
['\xd1\x8d\xd1\x82\xd0\xbe\xd1\x82', '\xd1\x82\xd0\xbe\xd1\x82', ['\xd0\xbe\xd0\xbd', '\xd0\xb4\xd1\x80\xd1\x83\xd0\xb3\xd0\xbe\xd0\xb9']]
>>> print list2
['\xd0\xbf\xd0\xbe\xd0\xba\xd0\xb0', '\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82']
>>>
надо заметить что в 3.0 этот код прекрасно работает(ещё как(!!!)):
# -*- coding: utf-8 -*-
>>> list1
['этот', 'тот', ['он', 'другой']]
>>> list2
['пока', 'привет']
>>> print(list1)
['этот', 'тот', ['он', 'другой']]
>>> print(list2)
['пока', 'привет']
Спросил на форуме наткнулся только на возмущенные советы читать гугл. Делать было нечего и в течении нескольких дней я, как прилежный мальчик читал интернеты, тысячи их.
И вот что я понял:
Все проблемы возникают от того что исполняемый код поставляет поток байтов в выходной поток, а выходной поток отображается в терминальное окно, но так как индетификатор потока никак не передаётся, то терминальное окно читает поток в той кодировке, которая в нём установленна.
Как оказалось кодировку терминала можно определить вызовом
>>> import sys
>>> sys.stdout.encoding
Интересно что
для командной строки питона 2.6 это cp866 для шелла питона 2.6 это cp1251 для командной строки питона 3.0 это cp866 а для питона шелла cp1251
(а что кстати делате такой вызов locale.getpreferredencoding() и в чём его отличие от sys.stdout.encoding?)

В роде разобрались в чём проблема…. в 2.6 не иначе.

Что делать?
Я прочитал и попробовал множество разных способов ни один меня полностью не удовлетворил. Далее в произвольном порядке(Все ниже сказанное относиться только к питону 2.6, т.к в 3.0 этой проблемы не возникает(или у меня пока не возникло))
Сразу договоримсячто все коды я хочу по православному писать в utf-8 т.е. кодировку всех файлов я устанавливаю как utf-8 и в начале каждого файла пишу
# -*- coding: utf-8 -*-
? таким образом яна шаг приближаюсь к созданию интернациональных приложений.

способ 1 “явное указание кодировки и преобразование при выводе” http://forum.script-coding.info/viewtopic.php?id=845
код:
# -*- coding: utf-8 -*-
print '1 ' 'привет мир'

print '2 ' u'Привет, Мир!'

y=['он','она',['они','оно']]
print '3', y

k=[u'он',u'она',[u'они',u'оно']]
print '4', k
ответ:
>>> 
1 привет мир
2 Привет, Мир!
3 ['\xd0\xbe\xd0\xbd', '\xd0\xbe\xd0\xbd\xd0\xb0', ['\xd0\xbe\xd0\xbd\xd0\xb8', '\xd0\xbe\xd0\xbd\xd0\xbe']]
4 [u'\u043e\u043d', u'\u043e\u043d\u0430', [u'\u043e\u043d\u0438', u'\u043e\u043d\u043e']]
>>>
как видно напечатать привет мир у нас уже получается, а вот список или словарь уже нет((((

способ 2 “обёртка для вывода”http://forum.script-coding.info/viewtopic.php?id=845
как я понимаю проблему, мы зададим окну вывода кодировку символьного потока. терминал будет читать из входного потока именно той кодировке, в которой мы туда будем символы отправлять.
код:
# -*- coding: utf-8 -*-
import codecs, sys
outf = codecs.getwriter('cp1251')(sys.stdout, errors='replace')
sys.stdout = outf
print >> outf, u'Первый пошёл!'
print u'Второй пошёл!'
outf.write(u'Третий пошёл!\n')

#print '0 ' 'Привет, Мир!' ошибка

print '1 ' u'Привет, Мир!'

y=['он','она',['они','оно']]
print '2', y

k=[u'он',u'она',[u'они',u'оно']]
print '3', k

print >> outf,'4', k

#outf.write(k) ошибка
#outf.write(y) ошибка
ответ
>>> 
Первый пошёл!
Второй пошёл!
Третий пошёл!
1 Привет, Мир!
2 ['\xd0\xbe\xd0\xbd', '\xd0\xbe\xd0\xbd\xd0\xb0', ['\xd0\xbe\xd0\xbd\xd0\xb8', '\xd0\xbe\xd0\xbd\xd0\xbe']]
3 [u'\u043e\u043d', u'\u043e\u043d\u0430', [u'\u043e\u043d\u0438', u'\u043e\u043d\u043e']]
4 [u'\u043e\u043d', u'\u043e\u043d\u0430', [u'\u043e\u043d\u0438', u'\u043e\u043d\u043e']]
>>>
Можем улучшить этот код добавив автоматическое определение кодировки:
# -*- coding: utf-8 -*-
import codecs, sys
code=sys.stdout.encoding
outf = codecs.getwriter(code)(sys.stdout, errors='replace')
sys.stdout = outf
print >> outf, u'Первый пошёл!'
print u'Второй пошёл!'
outf.write(u'Третий пошёл!\n')

#print '0 ' 'Привет, Мир!' ошибка

print '1 ' u'Привет, Мир!'

y=['он','она',['они','оно']]
print '2', y

k=[u'он',u'она',[u'они',u'оно']]
print '3', k

print '4', y

print >> outf,'4', k

print >> outf,'5', y

#outf.write(k) ошибка
#outf.write(y) ошибка
ответ:
>>> 
Первый пошёл!
Второй пошёл!
Третий пошёл!
1 Привет, Мир!
2 ['\xd0\xbe\xd0\xbd', '\xd0\xbe\xd0\xbd\xd0\xb0', ['\xd0\xbe\xd0\xbd\xd0\xb8', '\xd0\xbe\xd0\xbd\xd0\xbe']]
3 [u'\u043e\u043d', u'\u043e\u043d\u0430', [u'\u043e\u043d\u0438', u'\u043e\u043d\u043e']]
4 ['\xd0\xbe\xd0\xbd', '\xd0\xbe\xd0\xbd\xd0\xb0', ['\xd0\xbe\xd0\xbd\xd0\xb8', '\xd0\xbe\xd0\xbd\xd0\xbe']]
4 [u'\u043e\u043d', u'\u043e\u043d\u0430', [u'\u043e\u043d\u0438', u'\u043e\u043d\u043e']]
5 ['\xd0\xbe\xd0\xbd', '\xd0\xbe\xd0\xbd\xd0\xb0', ['\xd0\xbe\xd0\xbd\xd0\xb8', '\xd0\xbe\xd0\xbd\xd0\xbe']]
>>>
Подведём промежуточный итог - нам до сих пор не получилось корректно вывести список, хотя мы нашли кучу способов для вывода “привет мир”, ну чем не результат!? У меня такое подозрение, что единственный путь - писать самому функции которые выводили бы списки, словари, кортежди……. используя при этом явную перекодировку символов на входе программы и на выходе. а именно так: www.rupy.ru/static/files/07/02/12/rupyru2007-yurevich-unicode-thesis.pdf

Способ 3 http://pythonini.livejournal.com/14325.html
в теории всё просто:
# -*- coding: utf-8 -*-
# Конечно в нормальной жизни этих коментариев тут нет
# Загрузить кодеки и библиотеку локалей, установить дефолтную локаль согласно
# переменной окружения LC_ALL.
import locale, codecs; locale.setlocale(locale.LC_ALL, '')
# Теперь в encoding положим текущая кодировку локали.
encoding = locale.getlocale()[1]
# Если кодировка не определилась - это винды. Там полюбому UTF-8 :)
if not encoding:
encoding = "utf-8"
# Установим дефолтную локаль. Финт с ушами reload() нужен потому что разработчики
# питона дюже умные и логично удаляют функцию setdefaultencoding при загрузке.
# Оно в общем то логично, но я же умный.
import sys;reload(sys);sys.setdefaultencoding(encoding)
# Установили кодеки для вывода в потоки согласно распорядку.
sys.stdout = codecs.getwriter(encoding)(sys.stdout, errors = "replace")
sys.stderr = codecs.getwriter(encoding)(sys.stderr, errors = "replace")
на практике результаты этого способа очень сильно отличаются в командной строке в IDLE и в SciTE:
в командной сторке:
Python 2.6.1 (r261:67517, Dec  4 2008, 16:51:00) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import locale, codecs; locale.setlocale(locale.LC_ALL, '')
'Russian_Russia.1251'
>>> encoding = locale.getlocale()[1]
>>> import sys;reload(sys);sys.setdefaultencoding(encoding)
<module 'sys' (built-in)>
>>> sys.stdout = codecs.getwriter(encoding)(sys.stdout, errors = "replace")
>>> sys.stderr = codecs.getwriter(encoding)(sys.stderr, errors = "replace")
>>> print 'hellou world'
hellou world
>>> y=['он','она',['они','оно']]
>>> y
['\xae\xad', '\xae\xad\xa0', ['\xae\xad\xa8', '\xae\xad\xae']]
>>> print y
['\xae\xad', '\xae\xad\xa0', ['\xae\xad\xa8', '\xae\xad\xae']]
>>> k=[u'он',u'она',[u'они',u'оно']]
>>> k
[u'\u043e\u043d', u'\u043e\u043d\u0430', [u'\u043e\u043d\u0438', u'\u043e\u043d\
u043e']]
>>> print k
[u'\u043e\u043d', u'\u043e\u043d\u0430', [u'\u043e\u043d\u0438', u'\u043e\u043d\
u043e']]
>>>
>>> t='привет тебе'
>>> t
'\xaf\xe0\xa8\xa2\xa5\xe2 \xe2\xa5\xa1\xa5'
>>> print t
ЇаЁў?в в?Ў?
>>> print t.decode('utf-8')#в SciTE этот код работает'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python26\lib\encodings\utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xaf in position 0: unexpecte
d code byte
>>> print t.decode('cp1251')
ЇаЁў?в в?Ў?
>>> print t.decode('cp866')# в SciTE это не работает
привет тебе
>>> print encoding
1251
>>> print u'привет'
привет
>>> sys.stdout.encoding
'cp866'
>>> print type(sys.stdout.encoding)
<type 'str'>
в SciTE с установеленной строкой output.code.page=866
код:
# -*- coding: utf-8 -*-
# Конечно в нормальной жизни этих коментариев тут нет
# Загрузить кодеки и библиотеку локалей, установить дефолтную локаль согласно
# переменной окружения LC_ALL.
import locale, codecs; locale.setlocale(locale.LC_ALL, '')
# Теперь в encoding положим текущая кодировку локали.
encoding = locale.getlocale()[1]
print encoding
# Если кодировка не определилась - это винды. Там полюбому UTF-8 :)
if not encoding:
encoding = "utf-8"
# Установим дефолтную локаль. Финт с ушами reload() нужен потому что разработчики
# питона дюже умные и логично удаляют функцию setdefaultencoding при загрузке.
# Оно в общем то логично, но я же умный.
import sys;reload(sys);sys.setdefaultencoding(encoding)
# Установили кодеки для вывода в потоки согласно распорядку.
sys.stdout = codecs.getwriter(encoding)(sys.stdout, errors = "replace")
sys.stderr = codecs.getwriter(encoding)(sys.stderr, errors = "replace")


print '1 ' u'Привет, Мир!'

y=['он','она',['они','оно']]
print '2', y

k=[u'он',u'она',[u'они',u'оно']]
print '3', k

print '4', y

#print >> outf,'5', y
t='привет строка в юникод'
h=u'привет юникод'
h=t.decode('utf-8')

print type(h)
print type(t)
print t.decode('utf-8')
print t.decode('cp866')
print t.decode('cp1251')
print u"принт"
print k
print sys.stdout.encoding
print type(sys.stdout.encoding)
ответ:
>pythonw -u "kodinglokal.py"
1251
1 Привет, Мир!
2 ['\xd0\xbe\xd0\xbd', '\xd0\xbe\xd0\xbd\xd0\xb0', ['\xd0\xbe\xd0\xbd\xd0\xb8', '\xd0\xbe\xd0\xbd\xd0\xbe']]
3 [u'\u043e\u043d', u'\u043e\u043d\u0430', [u'\u043e\u043d\u0438', u'\u043e\u043d\u043e']]
4 ['\xd0\xbe\xd0\xbd', '\xd0\xbe\xd0\xbd\xd0\xb0', ['\xd0\xbe\xd0\xbd\xd0\xb8', '\xd0\xbe\xd0\xbd\xd0\xbe']]
<type 'unicode'>
<type 'str'>
привет строка в юникод
???А???????В ?Б?В?А?????? ?? ?О??????????
привет строка в юникод
принт
[u'\u043e\u043d', u'\u043e\u043d\u0430', [u'\u043e\u043d\u0438', u'\u043e\u043d\u043e']]
None
<type 'NoneType'>
>Exit code: 0 Time: 0.210
в IDLE код может и работает но так что ничего не видно. поток вывода проваливается куда-то…….

полезная справка:

setdefaultencoding(encoding)
Устанавливает кодировку, которая будет использоваться по умолчанию при пре образовании обычных строк в строки Unicode и наоборот. Если строка encoding не соответствует доступной кодировке, генерирует исключение LookupError. Эта функция предназначена для использования в модуле site (или sitecustomize), после этого она обычно удаляется из пространства имен модуля sys. Функция доступна, начиная с версии 2.0.

unicode(string [, encoding ])
Преобразует строку string из кодировки encoding (по умолчанию ’utf-8’) в строку Unicode и возвращает результат. Поведение при возникновении ошибок
определяется значением аргумента errors: ’strict’ (используется по умолчанию) означает, что при возникновении ошибки будет сгенерировано исключение UnicodeError, ’ignore’ — недопустимые символы игнорируются (удаляются), ’replace’ — недопустимые символы заменяются универсальным символом замены (“REPLACEMENT CHARACTER”, u’\uFFFD’).

LookupError
Базовый класс исключений, генерируемых, если последовательность или отображение не содержит элемента с заданным индек-
сом или ключом. Может быть сгенерировано напрямую функцией sys.setdefaultencoding().

sys.getdefaultencoding()
Возвращает текущую кодировку, используемую по умолчанию при преобразовании обычных строк в строки Unicode и наоборот. Функция доступна, начиная с версии 2.0.

Преобразования между типами строк

Строка > юникод
>>> regular_string = ’обычная строка’
>>> type(regular_string)
<type ’str’>
>>> unicode_string = regular_string.decode(’utf-8’)
>>> type(unicode_string)
<type ’unicode’>
Юникод > строка
>>> unicode_string = u’юникод-строка’
>>> type(unicode_string)
<type ’unicode’>
>>> regular_string = unicode_string.encode(’utf-8’)
>>> type(regular_string)
<type ’str’>
Заключение. Как вывести список? писать собственные функции?
beliy_shum
люди, то-ли я уж на столько ту что питон мне в и жисть не осилить, но вывести список кроме как собственной функцией я не могу. помогите пожалуйста, хотя бы с постановкой диагноза.
Андрей Светлов
Да. Для вывода своих списков - писать собственные функции для вывода сложных объектов в файл (список - тоже сложный, не смейтесь).
Строки держать только в юникоде (преобразовывая в байты только на момент чтения/записи).

Ваша проблема на самом деле при обычной разработке случается крайне редко. Просто потому, что если уж нужно что-то писать в файл - сначала делается ручное преобразование в строку (байты) нужной кодировки. С форматированием и прочими необходимыми вещами. А когда есть правильно кодированные байты - они пишутся куда угодно без проблем.

Манипуляциии с setpreferreddefaultencoding - плохая идея.

В вашем случае не срабатывает преобразование list=>unicode.

__unicode__( self)
Called to implement unicode() builtin; should return a Unicode object. When this method is not defined, string conversion is attempted, and the result of string conversion is converted to Unicode using the system default encoding.

А list=>str режет локаль.


Так дела обстоят с 2.6
pyuser
Андрей Светлов
… А когда есть правильно кодированные байты - они пишутся куда угодно без проблем. …
не всегда :( http://python.su/forum/viewtopic.php?id=3548&p=3 последний пост… ни кто так и не сказал, что я делал не правильно…
Александр Кошелев
Этот элемент точно также на forum.vingrad.ru отжигает. Похож на тролля.
beliy_shum
никакой я не тролль.
посмотри что отвечают людям про пробелему с кодировками:


Проблема много раз обсасывалась. Ищите на форуме
http://python.su/forum/viewtopic.php?id=4152

Сто раз обсуждалось на форуме… Попробуй воспользоваться поиском…
http://python.su/forum/viewtopic.php?id=4145

Не очень понятно что вы хотели сказат таким большим постом, тем более до сути вы так и не добралсь.
http://forum.vingrad.ru/forum/topic-255152/kw-python-%D0%BA%D0%BE%D0%B4%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8-%D0%B5%D0%BC%D1%8B-%D0%BA%D0%BE%D0%B4%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0%D0%BC%D0%B8.html

если бы с кодировками всё было так просто, то давно уже был бы написан на эту тему полноценный ответ который можно было бы новичкам давать ссылкой.
а ответа такого нет, и в большинстве своеём люди отвечают - “читай форум”
beliy_shum
Андрей Светлов
печально что это не проработано. спасибо разобрался боле мение
Андрей Светлов
Проработано в 3.0 и далее - по самое не могу. Но сейчас срочно переключаться на тройку не стоит. А в 2.7 изменений по локалям, затрагивающих проблему - не будет.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB