Читать символы Юникода из аргументов командной строки в Python 2.x в Windows
Я хочу, чтобы мой скрипт Python мог читать аргументы командной строки Unicode в Windows. Но похоже, что sys.argv-это строка, закодированная в некоторой локальной кодировке, а не в Юникоде. Как я могу прочитать командную строку в полном Unicode?
пример кода: argv.py
import sys
first_arg = sys.argv[1]
print first_arg
print type(first_arg)
print first_arg.encode("hex")
print open(first_arg)
на моем ПК, настроенном для японской кодовой страницы, я получаю:
C:temp>argv.py "PC・ソフト申請書08.09.24.doc"
PC・ソフト申請書08.09.24.doc
<type 'str'>
50438145835c83748367905c90bf8f9130382e30392e32342e646f63
<open file 'PC・ソフト申請書08.09.24.doc', mode 'r' at 0x00917D90>
это шифрование Shift-JIS, я считаю, и оно "работает" для этого имени файла. Но он ломается для имен файлов с символами это не в наборе символов Shift-JIS-окончательный" открытый " вызов не выполняется:
C:temp>argv.py Jörgen.txt
Jorgen.txt
<type 'str'>
4a6f7267656e2e747874
Traceback (most recent call last):
File "C:tempargv.py", line 7,
in <module>
print open(first_arg)
IOError: [Errno 2] No such file or directory: 'Jorgen.txt'
примечание-Я говорю о Python 2.x, а не Python 3.0. Я обнаружил, что Python 3.0 дает sys.argv
как правильный Unicode. Но еще немного рано переходить на Python 3.0 (из-за отсутствия поддержки сторонних библиотек).
обновление:
несколько ответов сказали, что я должен декодировать в соответствии с тем, что sys.argv
кодируется. Проблема в том, что это не полный Unicode, поэтому некоторые символы не представимое.
вот прецедент, который дает мне горе: у меня есть поддержкой drag-и-Drop файлов на .py файлов в Проводнике Windows. У меня есть имена файлов со всеми видами символов, включая некоторые не в системной кодовой странице по умолчанию. Мой скрипт Python не получает правильные имена файлов Unicode, переданные ему через sys.argv во всех случаях, когда символы не представляются на текущей кодовой странице кодирование.
конечно, есть некоторый Windows API для чтения командной строки с полным Unicode (и Python 3.0 делает это). Я предполагаю Python 2.интерпретатор x не использует его.
4 ответов
вот решение, которое именно то, что я ищу, делая вызов Windows GetCommandLineArgvW
функция:
получить sys.argv с символами Юникода под Windows (из ActiveState)
но я сделал несколько изменений, чтобы упростить его использование и лучше обрабатывать определенные виды использования. Вот что я использую:
win32_unicode_argv.py
"""
win32_unicode_argv.py
Importing this will replace sys.argv with a full Unicode form.
Windows only.
From this site, with adaptations:
http://code.activestate.com/recipes/572200/
Usage: simply import this module into a script. sys.argv is changed to
be a list of Unicode strings.
"""
import sys
def win32_unicode_argv():
"""Uses shell32.GetCommandLineArgvW to get sys.argv as a list of Unicode
strings.
Versions 2.x of Python don't support Unicode in sys.argv on
Windows, with the underlying Windows API instead replacing multi-byte
characters with '?'.
"""
from ctypes import POINTER, byref, cdll, c_int, windll
from ctypes.wintypes import LPCWSTR, LPWSTR
GetCommandLineW = cdll.kernel32.GetCommandLineW
GetCommandLineW.argtypes = []
GetCommandLineW.restype = LPCWSTR
CommandLineToArgvW = windll.shell32.CommandLineToArgvW
CommandLineToArgvW.argtypes = [LPCWSTR, POINTER(c_int)]
CommandLineToArgvW.restype = POINTER(LPWSTR)
cmd = GetCommandLineW()
argc = c_int(0)
argv = CommandLineToArgvW(cmd, byref(argc))
if argc.value > 0:
# Remove Python executable and commands if present
start = argc.value - len(sys.argv)
return [argv[i] for i in
xrange(start, argc.value)]
sys.argv = win32_unicode_argv()
теперь, как я использую это просто сделать:
import sys
import win32_unicode_argv
и дальше sys.argv
is список строк Юникода. Питон optparse
модуль, кажется, рад разобрать его, что здорово.
работа с кодировками очень запутанной.
Я верить если ваши inputing данные через командную строку он будет кодировать данные, как независимо от вашей системной кодировки и не unicode. (Даже копировать/вставить должно сделать это)
поэтому следует правильно декодировать в unicode, используя системную кодировку:
import sys
first_arg = sys.argv[1]
print first_arg
print type(first_arg)
first_arg_unicode = first_arg.decode(sys.getfilesystemencoding())
print first_arg_unicode
print type(first_arg_unicode)
f = codecs.open(first_arg_unicode, 'r', 'utf-8')
unicode_text = f.read()
print type(unicode_text)
print unicode_text.encode(sys.getfilesystemencoding())
запуск следующего вывода: Запрос> python myargv.py " PC -フフト申請書08.09.24.txt"
PC・ソフト申請書08.09.24.txt
<type 'str'>
<type 'unicode'>
PC・ソフト申請書08.09.24.txt
<type 'unicode'>
?日本語
где "PC -フフト申請書08.09.24.txt "содержал текст "日本語". (Я закодировал файл как utf8 с помощью Windows notepad, я немного озадачен тем, почему есть"?- в начале, когда печатали. Что-то связано с тем, как блокнот сохраняет в utf8?)
метод декодирования строк или встроенный unicode () можно использовать для преобразования кодировки в unicode.
unicode_str = utf8_str.decode('utf8')
unicode_str = unicode(utf8_str, 'utf8')
кроме того, если вы имеете дело с закодированными файлами, вы можете использовать кодеки.функция open () вместо встроенной функции open (). Он позволяет определить кодировку файла, а затем будет использовать данную кодировку для прозрачного декодирования содержимого в unicode.
поэтому, когда вы называете content = codecs.open("myfile.txt", "r", "utf8").read()
content
будет в юникоде.
кодеки.открыть: http://docs.python.org/library/codecs.html?#codecs.open
если я что-то не понимаю, пожалуйста, дайте мне знать.
если вы еще этого не сделали, я рекомендую прочитать статью Джоэла о unicode и кодирование: http://www.joelonsoftware.com/articles/Unicode.html
попробуйте это:
import sys
print repr(sys.argv[1].decode('UTF-8'))
Возможно, вам придется заменить CP437
или CP1252
на UTF-8
. Вы должны иметь возможность вывести правильное имя кодировки из раздела реестра HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage\OEMCP
командная строка должна быть в кодировке Windows. Попробуйте декодировать аргументы в unicode
объекты:
args = [unicode(x, "iso-8859-9") for x in sys.argv]