Lisez les caractères Unicode des arguments en ligne de commande dans Python 2.X sur Windows

je veux que mon script Python puisse lire les arguments en ligne de commande Unicode sous Windows. Mais il semble que sys.argv est une chaîne de caractères encodée dans un encodage local, plutôt qu'Unicode. Comment puis-je lire la ligne de commande en Unicode?

exemple de code: 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)

sur mon PC mis en place pour la page de code japonais, je reçois:

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>

C'est Shift-JIS codé je crois, et ça "marche" pour ça filename. Mais il casse pour les noms de fichiers avec des caractères qui ne sont pas dans le jeu de caractères Shift-JIS-l'appel final" open "échoue:

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'

Note-je parle de Python 2.x, Pas Python 3.0. J'ai trouvé que Python 3.0 donne sys.argv comme Unicode approprié. Mais il est encore un peu tôt pour passer à Python 3.0 (en raison du manque de support pour les bibliothèques tierces).

mise à jour:

quelques réponses ont dit que je devrait décoder selon ce que le sys.argv est encodé. Le problème avec ça c'est que ce N'est pas Unicode complet, donc certains caractères ne sont pas représentables.

voici le cas d'utilisation qui me donne du chagrin: j'ai permis glisser-déposer des fichiers sur .fichiers py dans L'Explorateur de Windows . J'ai des noms de fichiers avec toutes sortes de caractères, y compris certains qui ne sont pas dans la page de code par défaut du système. Mon script Python ne passe pas les bons noms de fichiers Unicode via sys.argv dans tous les cas, lorsque les caractères ne sont pas représentables dans la page de code en cours d'encodage.

il y a certainement une API Windows pour lire la ligne de commande avec Unicode complet (et Python 3.0 le fait). Je suppose le Python 2.x interpreter ne l'utilise pas.

29
demandé sur Community 2009-05-11 09:44:02

4 réponses

Voici une solution qui est exactement ce que je cherche, faire un appel à la fonction Windows GetCommandLineArgvW :

va chercher sys.argv avec caractères Unicode sous Windows (de ActiveState)

mais j'ai fait plusieurs changements, pour simplifier son utilisation et mieux gérer certaines utilisations. Voici ce que j'utilise:

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()

maintenant, le la façon dont je l'utilise est simplement de faire:

import sys
import win32_unicode_argv

et à partir de là, sys.argv est une liste de chaînes Unicode. Le module Python optparse semble heureux de l'analyser, ce qui est génial.

29
répondu Craig McQueen 2009-11-23 06:02:46

le traitement des encodages est très confus.

je croire si votre entrée de données via la ligne de commande, il va encoder les données quel que soit votre système d'encodage est et n'est pas unicode. (Même copier/coller devrait faire cela)

il doit donc être correct de décoder en unicode en utilisant le codage du système:

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())

exécuter la sortie suivante: Invite> python myargv.py "PC-manda08.09.484.txt "

PC・ソフト申請書08.09.24.txt
<type 'str'>
<type 'unicode'>
PC・ソフト申請書08.09.24.txt
<type 'unicode'>
?日本語

où le " PC-pontage08.09.484.txt" contient le texte, "日本語". (J'ai encodé le fichier en utf8 en utilisant Windows notepad, je suis un peu perplexe quant à savoir pourquoi il y a un '?'au début, lors de l'impression. Quelque chose à voir avec la façon dont le bloc-notes sauve utf8?)

la méthode strings 'decode' ou l'option unicode() peut être utilisée pour convertir un encodage en unicode.

unicode_str = utf8_str.decode('utf8')
unicode_str = unicode(utf8_str, 'utf8')

aussi, si vous traitez avec les fichiers encodés vous pouvez utiliser les codecs.fonction open() à la place de l'intégré dans le open(). Il permet de définir l'encodage du fichier, et ensuite utiliser le codage donnée de manière transparente décoder le contenu au format unicode.

donc quand vous appelez content = codecs.open("myfile.txt", "r", "utf8").read() content sera en unicode.

codecs.ouvrir: http://docs.python.org/library/codecs.html?#codecs.open

si Je ne comprends pas quelque chose s'il vous plaît laissez-moi savoir.

si vous ne l'avez pas encore fait, je vous recommande la lecture de L'article de Joel sur unicode et encodage: http://www.joelonsoftware.com/articles/Unicode.html

11
répondu monkut 2012-04-26 00:25:38

essayez ceci:

import sys
print repr(sys.argv[1].decode('UTF-8'))

peut-être que vous devez remplacer UTF-8 par CP437 ou CP1252 . Vous devriez être en mesure de déduire le nom d'encodage approprié à partir de la clé de registre HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage\OEMCP

2
répondu pts 2009-05-11 05:58:33

la ligne de commande peut être codée par Windows. Essayez de décoder les arguments en unicode objets:

args = [unicode(x, "iso-8859-9") for x in sys.argv]
0
répondu a paid nerd 2009-05-11 06:03:11