Уведомления

Группа в Telegram: @pythonsu

#1 Ноя. 18, 2009 11:03:48

gman
От:
Зарегистрирован: 2009-03-12
Сообщения: 10
Репутация: +  0  -
Профиль   Отправить e-mail  

sys.argv и кодировка

Ситуация такая:

C:\> type a.py
# -*- coding: cp866 -*-
import sys
a = "п"
b = sys.argv[1]
print ord(a), a
print ord(b), b

C:\> a.py п
175 п
239 я

C:\> chcp
Текущая кодовая страница: 866
то-есть все обменивается по cp866 а вот аргументы из sys.argv получаются в cp1251. Почему так происходит? перекодирование из 1251 в 866 не подходит как решение, поскольку на ввод будут поступать и символы псевдографики, которых нет в 1251. Компромисс с заменой аргумента на интерактивный ввод (raw_input()) идеологически не подходит. Помогите пожалуйста, ну совсем изгуглился, может можно как-то заставить sys.argv принимать аргументы в нужной кодировке, ну или на крайний случай какой-то альтернативный вариант.
( ОС: WinXP, терминал стандартный )



Офлайн

#2 Ноя. 18, 2009 15:39:27

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

sys.argv и кодировка

лучше кодить в utf-8,

# -*- coding: utf-8 -*-
b = sys.argv[1].decode('cp866')
#b = sys.argv[1].decode('cp1251')

Офлайн

#3 Ноя. 18, 2009 17:21:32

gman
От:
Зарегистрирован: 2009-03-12
Сообщения: 10
Репутация: +  0  -
Профиль   Отправить e-mail  

sys.argv и кодировка

Так уже пробовал, к сожалению не работает, можно перекодировать так b = unicode(sys.argv, “cp1251”).encode(“cp866”) но ето не подходит поскольку если на вход мы дадим чтото вроде “▓” то после пере кодировки получим “-”, потому-что таких символов в cp1251 просто нет.

# -*- coding: utf-8 -*-
import sys
b = sys.argv[1].decode('cp866')
print ord(b), b
запускаю: a.py й
получаю: 1097 щ
а должен: 169 й
лучше кодить в utf-8
лучше, вам, мне, но не тому для кого я кодю.



Офлайн

#4 Ноя. 18, 2009 19:15:12

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

sys.argv и кодировка

У вас же винда? Можно просто в лоб: GetCommandLineW/CommandLineToArgvW. Потребуется еще LocalFree. Завернуть все через ctypes - и будут юникодные command line arguments. А дальше уже не важно, cp866 вам нужна или 1251.



Офлайн

#5 Ноя. 18, 2009 20:51:06

gman
От:
Зарегистрирован: 2009-03-12
Сообщения: 10
Репутация: +  0  -
Профиль   Отправить e-mail  

sys.argv и кодировка

Андрей Светлов
У вас же винда? Можно просто в лоб: GetCommandLineW/CommandLineToArgvW. Потребуется еще LocalFree. Завернуть все через ctypes - и будут юникодные command line arguments. А дальше уже не важно, cp866 вам нужна или 1251.
спасибо, кое как получается но это тоже не вариант, WinAPI для такой цели это уже перебор. Нужно выяснить почему sys.argv снимает аргументы в кодировке 1251. Наверное потому-что locale.getpreferredencoding() возвращает cp1251, а то-есть кодировку для текстовых данных
Return the encoding used for text data, according to user preferences.
и как ее бы изменить?



Офлайн

#6 Ноя. 18, 2009 21:24:06

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

sys.argv и кодировка

gman
получаю: 1097 щ
ясен перец, мы ж в уникод перевели, из него можно в любой другой переводить
раз тебе нужн ср866, вот:
# -*- coding: cp866 -*-
import sys
a = "п"
b = sys.argv[1].decode('cp1251').encode('cp866')
print ord(a), a
print ord(b), b
результат:
>test1.py п
175 п
175 п

Офлайн

#7 Ноя. 18, 2009 21:53:55

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

sys.argv и кодировка

Изменить кодировку можно.
Она ставится в site.py самом конце как sys.setdefaultencoding
Можно положить куда-нибудь в путь, который попадает в sys.path (рядом с самим скриптом, например) sitecustomize.py.
И вызвать в нем sys.setdefaultencoding - но это будет означать, что для вашего скрипта кодировка изменится глобально.
Вам именно это нужно?



Офлайн

#8 Ноя. 18, 2009 23:15:54

gman
От:
Зарегистрирован: 2009-03-12
Сообщения: 10
Репутация: +  0  -
Профиль   Отправить e-mail  

sys.argv и кодировка

to o7412369815963
я уже писал почему перекодирование не подходит.

Андрей Светлов
Изменить кодировку можно.
Она ставится в site.py самом конце как sys.setdefaultencoding
Можно положить куда-нибудь в путь, который попадает в sys.path (рядом с самим скриптом, например) sitecustomize.py.
И вызвать в нем sys.setdefaultencoding - но это будет означать, что для вашего скрипта кодировка изменится глобально.
Вам именно это нужно?
да, а почему нельзя вызывать sys.setdefaultencoding() внутри скрипта? Вот вроде отрабатывает, но изменений нет:
# -*- coding: cp866 -*-
import sys
reload(sys)
print "old:", sys.getdefaultencoding()
sys.setdefaultencoding("cp866")
print "new:", sys.getdefaultencoding()
a = "п"
b = sys.argv[1]
print ord(a), a
print ord(b), b

> a.py п
old: ascii
new: cp866
175 п
239 я



Офлайн

#9 Ноя. 19, 2009 01:10:35

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

sys.argv и кодировка

Извините, но я ошибся по поводу sitecustomize (не люблю его, ох как сильно - слишком много раз приходилось “выкусывать” sitecustomize из кода проектов).
Так вот, он вам не поможет.

Наконец-то посмотрел в исходники питона.
Что увидел: initmain вызывается перед initsite, который в свою очередь дергает sitecustomize. Это все - импорты, а не запуск модулей. Поэтому на момент окончания шабаша __main__ не видит setdefaultencoding. Трюк с перезагрузкой sys вообще бесполезен при правильном использовании.

А argv запоминается именно в initmain - и потом не меняется. Я просто раньше для сложных случаев строил свой “python.exe запускач” - и там рулил питоном как хотел - у него несколько шагов по запуску интерпретатора, в каждый можно влезть на уровне C API.
Запоминается, подчеркну, в C API ядре. И потом его снаружи поменять - никак.

Нет, все таки можно - поскольку sys.argv честный список:
for i in xrange(sys.argv):
sys.argv = sys.argv.encode('cp1251').decode('cp866')


Или вы делаете свою “запускачку” питона - где command line arguments будут поданы правильно - или таки юзаете windows api как я предлагал (второй вариант проще, ИМХО).

P.S. Когда я на PyCon взялся чинить баг с кодировками в import - на меня посмотрели странно. Т.е. - это конечно баг, и чинить его нужно. Только на наших маках и юниксах (ни у кого из разработчиков ядра не видел, для них мак - это ноутбук, а юникс/линукс - серверная платформа) - вашей беды не видать, все в utf-8. Хорошо у них :)



Отредактировано (Ноя. 19, 2009 01:21:20)

Офлайн

#10 Ноя. 19, 2009 13:48:26

gman
От:
Зарегистрирован: 2009-03-12
Сообщения: 10
Репутация: +  0  -
Профиль   Отправить e-mail  

sys.argv и кодировка

Андрей Светлов
P.S. Когда я на PyCon взялся чинить баг с кодировками в import - на меня посмотрели странно. Т.е. - это конечно баг, и чинить его нужно. Только на наших маках и юниксах (ни у кого из разработчиков ядра не видел, для них мак - это ноутбук, а юникс/линукс - серверная платформа) - вашей беды не видать, все в utf-8. Хорошо у них :)
я сам проблем с кодировками в python никогда не-знал, поскольку раньше писал исключительно под себя, исключительно под linux, и соответственно в utf-8. А тут взялся помочь человеку с курсачем, и стал прозревать с того какие они эти “проблемы с кодировками”, и как криво умеет работать виндовый терминал/какие у меня кривые руки (cp1251 он корректно отображает только со шрифтом Lucida Console). По этому важно не только рабочее решение, но и простое, которое студент сможет пошагово аргументировать(не зная python), ведь слова вроде: …а здесь мы с помощь модуля ctypes прибегнем к WinAPI для того чтоб снять аргумент запуска… или: …воспользуемся альтернативным ланчером python.exe для того чтоб обявить кодирову на єтапе initmain… это просто смешно.
Учитывая что проблема столь глубоко, придется прибегнуть к халтурке.



Отредактировано (Ноя. 19, 2009 13:55:49)

Офлайн

Board footer

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

Powered by DjangoBB

Lo-Fi Version