Уведомления

Группа в Telegram: @pythonsu

#1 Ноя. 14, 2007 10:39:49

The gray Cardinal
От:
Зарегистрирован: 2007-03-07
Сообщения: 422
Репутация: +  0  -
Профиль   Отправить e-mail  

SciTE, проблема с кодировками

SciTE, WinXP.

# -*- coding: utf-8 -*-
print u'Привет, Мир!'
# -*- coding: cp1251 -*-
print unicode('Привет, Мир!', 'cp1251')
В обоих случаях при запуске из-под SciTE (F5) получается следующее:
UnicodeEncodeError: ‘ascii’ codec can't encode characters in position 0-5: ordinal not in range(128)
Вне SciTE всё работает правильно. Как побороть SciTE?



Офлайн

#2 Ноя. 14, 2007 12:17:24

bialix
От:
Зарегистрирован: 2006-07-13
Сообщения: 774
Репутация: +  1  -
Профиль   Отправить e-mail  

SciTE, проблема с кодировками

как обычно вопрос не в SciTe или XXX (подставить любой редактор или инструмент), а в том, что 99,99999% питон-программистов не понимают, что печатать unicode строки в общем случае НЕЛЬЗЯ!!! Возьмите ручку и напишите 1000 раз на листике бумаги: Я НИКОГДА НЕ БУДУ ПЕЧАТАТЬ UNICODE-СТРОКИ

Когда вы работаете интерактивно, то ваш sys.stdout подключен к реальному терминальному окну. К РЕАЛЬНОМУ. Которе имеет конечно какую-то дефолтную кодировку выводимых символов. Питон при старте интерпретатора ловит наличие реального терминала, определяет какая кодировка там используется и создает специальную ОБВЕРТКУ вокруг потока STDOUT, которая обеспечивает перекодирование unicode-символов. Именно с этой обверткой мы имеем дело, когда говорим sys.stdout.

Когда же питон-скрипт вызывается как субпроцесс (сюрпрайз-сюрпрайз! именно так запускают скрипты почти все редакторы, чтобы перехватить вывод интерпретатор и показать его красиво в своем специальном окне), ИЛИ же вывод скрипта перенаправляется в файл или через pipe в программу типа less или more:

python script.py > file.log
python script.py | more

то у нас нет реального терминала. Есть просто поток вывода. Файловый поток. Который ничего не знает о кодировках.

В этом случае при старте питон интерпретатора для потока sys.stdout никакой перекодирующей обвертки не создается! И вот тут-то все не-ascii программисты и пользователи ловят UnicodeDecodeError. И начинается: о ужас! что же делать??? SciTe глючит! XXX глюкало! на помойку!

Товарищи! Выкиньте на помойку свои примитивные программы или по крайней мере забудьте о том, что символы с кодом больше 127 вообще существуют.

Кто виноват мы вроде разобрались.

Теперь: что делать.

А делать надо вот что.
Самый правильный и занудный вариант: никогда не печатать юникодные строки, а перекодировать их ручками в нужную кодировку: print unistr.encode('cp1251')
Только руки устанут кодировать такое.

Другой правильный путь (он более сложный, но не занудный):
1) проверить что sys.stdout подключен к реальному терминалу: sys.stdout.isatty()
2) если не подключен, что делаем обвертку руками:

import codecs
outf = codecs.getwriter('cp1251')(sys.stdout)
и использовать поток outf для вывода ваших замечательных юникодных строк.
Можно даже подменить sys.stdout этой обверткой.
И помните, что до создания обвертки никакие юникодные символы вы печатать не можете! вапще.

3) Вместо cp1251 надо бы подставлять кодировку пользователя, иначе ваша прога будет работать только для русской винды. И в терминале вобщето надо юзать cp866, если вы не используете команду chcp конечно. Для того, чтобы определить кодировку терминала надо немного больше усилий. Мне щас лень копи-пастить код, но в исходниках проекта Базаар это реализовано как надо в лучшем кросс-платформенном виде.

Да и еще. Обвертку outf имеет создавать дя вывода всегда, даже когда у вас присутствует реальный терминал. А то захотите вы нечаянно напечатать какой-нить китайский иероглиф в русской консоли – и опять поймаете UnicodeEncodeError. Только при создании обвертки надо юзать необязательный аргумент errors:

outf = codecs.getwriter('cp1251')(sys.stdout, errors='replace')

и все непечатные символы будут подменены вопросиками. Другое дело, что вам может быть не всегда это нужно. Дальше думайте своей головой, пожалуйста.



Офлайн

#3 Ноя. 14, 2007 13:15:31

The gray Cardinal
От:
Зарегистрирован: 2007-03-07
Сообщения: 422
Репутация: +  0  -
Профиль   Отправить e-mail  

SciTE, проблема с кодировками

bialix
Спасибо большое, отличная статья!
Но. Чтобы эта статья была действительно полезна для тех, кому она и предназначена (т.е. для новичков), нужно решить несколько моментов.

1.

bialix
…и использовать поток outf для вывода ваших замечательных юникодных строк.
Здесь обязательно нужен пример кода.

2.
bialix
Можно даже подменить sys.stdout этой обверткой.
Здесь обязательно нужен пример кода.

3.
bialix
Для того, чтобы определить кодировку терминала надо немного больше усилий. Мне щас лень копи-пастить код…
Огромная, дикая просьба от лица всего начинающего-русскоязычного-питонопишушего человечества преодолеть лень :).

Если эти поправки будут сделаны, будет просто великолепная статья.



Офлайн

#4 Ноя. 14, 2007 19:33:17

bialix
От:
Зарегистрирован: 2006-07-13
Сообщения: 774
Репутация: +  1  -
Профиль   Отправить e-mail  

SciTE, проблема с кодировками

The gray Cardinal
bialix
Спасибо большое, отличная статья!
Но. Чтобы эта статья была действительно полезна для тех, кому она и предназначена (т.е. для новичков), нужно решить несколько моментов.
С вашими замечаниями согласен, ибо тема эта действительно наболела.
И с выходом Python 3000 все станет только хуже.



Офлайн

#5 Ноя. 14, 2007 19:54:23

shiza
От:
Зарегистрирован: 2007-07-03
Сообщения: 1073
Репутация: +  0  -
Профиль   Отправить e-mail  

SciTE, проблема с кодировками

Не совсем верно.
На самом деле бывают и юникодные терминалы %).
Например - попробуйте в IDLE сделать вывод.

Как вывод:
Надо просто осознавать - какой у вас терминал.



Отредактировано (Ноя. 14, 2007 19:56:00)

Офлайн

#6 Ноя. 15, 2007 13:31:43

Все ники заняты
От:
Зарегистрирован: 2007-02-18
Сообщения: 156
Репутация: +  1  -
Профиль   Отправить e-mail  

SciTE, проблема с кодировками

bialix
Самый правильный и занудный вариант: никогда не печатать юникодные строки, а перекодировать их ручками в нужную кодировку: print unistr.encode('cp1251')
# -*- coding: utf-8 -*-
print u'Привет!'.encode('cp866')
В консоли нормально, в SciTE - кракозябры.
bialix
использовать поток outf для вывода ваших замечательных юникодных строк
# -*- coding: utf-8 -*-
import codecs, sys
outf = codecs.getwriter('cp866')(sys.stdout)
print >> outf, u'Привет!'
В консоли нормально, в SciTE - кракозябры.



Отредактировано (Ноя. 15, 2007 13:33:28)

Офлайн

#7 Ноя. 15, 2007 14:53:09

poltergeist
От:
Зарегистрирован: 2007-02-28
Сообщения: 522
Репутация: +  0  -
Профиль   Отправить e-mail  

SciTE, проблема с кодировками

Не знаю как у вас (Все ники заняты), но у меня SciTe настроен на юникод: в глобальных опциях стоит “code.page=65001” и “output.code.page=65001” (все исходные файлы в utf-8).

Вот этот вариант работает у меня в SciTe:

import codecs, sys
outf = codecs.getwriter('utf-8')(sys.stdout)
print >> outf, u'Привет!'


И опять же, какой редактор (терминал) - так он и покажет. Надо определиться и выбрать что-то одно, я вообще не вижу для себя смысла выводить юникодные строки, есть (будет) лог программы, который и будет понимать меня так, как я хочу - тогда я вообще избавлюсь от всех print-ов, тем более что в python3000 их всё равно надо будет переделывать, хоть и будут (есть) средства автоматизации этого процесса.



Офлайн

#8 Ноя. 15, 2007 15:19:05

Все ники заняты
От:
Зарегистрирован: 2007-02-18
Сообщения: 156
Репутация: +  1  -
Профиль   Отправить e-mail  

SciTE, проблема с кодировками

Сейчас поставил в SciTE:

code.page=65001
output.code.page=65001
Код:
# -*- coding: utf-8 -*-
import codecs, sys
outf = codecs.getwriter('utf-8')(sys.stdout)
print >> outf, u'Привет!'
Вывод:
>pythonw -u “test.py”
ǟT&̦-ƦT¡
>Exit code: 0 Time: 0.212



Офлайн

#9 Ноя. 15, 2007 16:41:18

shiza
От:
Зарегистрирован: 2007-07-03
Сообщения: 1073
Репутация: +  0  -
Профиль   Отправить e-mail  

SciTE, проблема с кодировками

Еще есть такая штука как
import sys
sys.stdout.encoding
Возвращает кодировку терминала. Но не во всех редакторах ее можно получить.



Отредактировано (Ноя. 15, 2007 16:43:33)

Офлайн

#10 Ноя. 15, 2007 17:09:25

Все ники заняты
От:
Зарегистрирован: 2007-02-18
Сообщения: 156
Репутация: +  1  -
Профиль   Отправить e-mail  

SciTE, проблема с кодировками

shiza
Еще есть такая штука как
import sys
sys.stdout.encoding
Возвращает кодировку терминала. Но не во всех редакторах ее можно получить.
В консоли у меня это - cp866.
Из-под SciTE - None.
codecs.getwriter('utf-8')(sys.stdout).encoding - то же самое, т.е. в консоли - cp866, из-под SciTE - None.
Только что это всё мне даёт?



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version