小编典典

在Windows上的Python 2.x中从命令行参数读取Unicode字符

python

我希望我的Python脚本能够在Windows中读取Unicode命令行参数。但是看来sys.argv是用某种本地编码而不是Unicode编码的字符串。如何阅读完整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)

在为日语代码页设置的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编码的内容进行解码。问题在于它不是完整的Unicode,因此某些字符无法表示。

这是让我感到悲伤的用例:我已在Windows资源管理器中将文件拖放到.py文件中。我的文件名带有各种字符,包括某些不在系统默认代码页中的字符。当在当前代码页编码中无法表示字符时,在所有情况下,我的Python脚本都无法通过sys.argv传递正确的Unicode文件名。

当然,有一些Windows API可以读取具有完整Unicode的命令行(Python 3.0可以做到)。我假设Python 2.x解释器未使用它。


阅读 228

收藏
2020-12-20

共1个答案

小编典典

这是我要寻找的解决方案,它调用WindowsGetCommandLineArgvW函数:
在Windows下从ActiveState获取带有Unicode字符的sys.argv

但是我进行了一些更改,以简化其用法并更好地处理某些用法。这是我用的:

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模块似乎很高兴解析它,这很棒。

2020-12-20