我希望我的Python脚本能够在Windows中读取Unicode命令行参数。但是看来sys.argv是用某种本地编码而不是Unicode编码的字符串。如何阅读完整Unicode的命令行?
示例代码: argv.py
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)
在为日语代码页设置的PC上,我得到:
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:\temp\argv.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
更新:
有几个回答说我应该根据sys.argv编码的内容进行解码。问题在于它不是完整的Unicode,因此某些字符无法表示。
这是让我感到悲伤的用例:我已在Windows资源管理器中将文件拖放到.py文件中。我的文件名带有各种字符,包括某些不在系统默认代码页中的字符。当在当前代码页编码中无法表示字符时,在所有情况下,我的Python脚本都无法通过sys.argv传递正确的Unicode文件名。
当然,有一些Windows API可以读取具有完整Unicode的命令行(Python 3.0可以做到)。我假设Python 2.x解释器未使用它。
这是我要寻找的解决方案,它调用WindowsGetCommandLineArgvW函数: 在Windows下从ActiveState获取带有Unicode字符的sys.argv
GetCommandLineArgvW
但是我进行了一些更改,以简化其用法并更好地处理某些用法。这是我用的:
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是Unicode字符串列表。Pythonoptparse模块似乎很高兴解析它,这很棒。
optparse