Найти - Пользователи
Полная версия: SciTE, проблема с кодировками
Начало » Инструментальные средства разработки » SciTE, проблема с кодировками
1 2 3
The gray Cardinal
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?
bialix
как обычно вопрос не в 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')

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

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

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

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

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

Как вывод:
Надо просто осознавать - какой у вас терминал.
Все ники заняты
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 - кракозябры.
poltergeist
Не знаю как у вас (Все ники заняты), но у меня 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 их всё равно надо будет переделывать, хоть и будут (есть) средства автоматизации этого процесса.
Все ники заняты
Сейчас поставил в 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
shiza
Еще есть такая штука как
import sys
sys.stdout.encoding
Возвращает кодировку терминала. Но не во всех редакторах ее можно получить.
Все ники заняты
shiza
Еще есть такая штука как
import sys
sys.stdout.encoding
Возвращает кодировку терминала. Но не во всех редакторах ее можно получить.
В консоли у меня это - cp866.
Из-под SciTE - None.
codecs.getwriter('utf-8')(sys.stdout).encoding - то же самое, т.е. в консоли - cp866, из-под SciTE - None.
Только что это всё мне даёт?
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