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.
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.
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
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
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]