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

发布于 2021-01-29 19:36:42

我希望我的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解释器未使用它。

关注者
0
被浏览
90
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    这是我要寻找的解决方案,它调用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模块似乎很高兴解析它,这很棒。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看