Найти - Пользователи
Полная версия: sys.argv и кодировка
Начало » Python для новичков » sys.argv и кодировка
1
gman
Ситуация такая:
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, терминал стандартный )
o7412369815963
лучше кодить в utf-8,

# -*- coding: utf-8 -*-
b = sys.argv[1].decode('cp866')
#b = sys.argv[1].decode('cp1251')
gman
Так уже пробовал, к сожалению не работает, можно перекодировать так 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
лучше, вам, мне, но не тому для кого я кодю.
Андрей Светлов
У вас же винда? Можно просто в лоб: GetCommandLineW/CommandLineToArgvW. Потребуется еще LocalFree. Завернуть все через ctypes - и будут юникодные command line arguments. А дальше уже не важно, cp866 вам нужна или 1251.
gman
Андрей Светлов
У вас же винда? Можно просто в лоб: 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.
и как ее бы изменить?
o7412369815963
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 п
Андрей Светлов
Изменить кодировку можно.
Она ставится в site.py самом конце как sys.setdefaultencoding
Можно положить куда-нибудь в путь, который попадает в sys.path (рядом с самим скриптом, например) sitecustomize.py.
И вызвать в нем sys.setdefaultencoding - но это будет означать, что для вашего скрипта кодировка изменится глобально.
Вам именно это нужно?
gman
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 я
Андрей Светлов
Извините, но я ошибся по поводу 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. Хорошо у них :)
gman
Андрей Светлов
P.S. Когда я на PyCon взялся чинить баг с кодировками в import - на меня посмотрели странно. Т.е. - это конечно баг, и чинить его нужно. Только на наших маках и юниксах (ни у кого из разработчиков ядра не видел, для них мак - это ноутбук, а юникс/линукс - серверная платформа) - вашей беды не видать, все в utf-8. Хорошо у них :)
я сам проблем с кодировками в python никогда не-знал, поскольку раньше писал исключительно под себя, исключительно под linux, и соответственно в utf-8. А тут взялся помочь человеку с курсачем, и стал прозревать с того какие они эти “проблемы с кодировками”, и как криво умеет работать виндовый терминал/какие у меня кривые руки (cp1251 он корректно отображает только со шрифтом Lucida Console). По этому важно не только рабочее решение, но и простое, которое студент сможет пошагово аргументировать(не зная python), ведь слова вроде: …а здесь мы с помощь модуля ctypes прибегнем к WinAPI для того чтоб снять аргумент запуска… или: …воспользуемся альтернативным ланчером python.exe для того чтоб обявить кодирову на єтапе initmain… это просто смешно.
Учитывая что проблема столь глубоко, придется прибегнуть к халтурке.
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