Leggi i caratteri Unicode da argomenti della riga di comando in Python 2.x su Windows
-
21-08-2019 - |
Domanda
Voglio che il mio script Python per essere in grado di leggere gli argomenti della riga di comando Unicode in Windows. Ma sembra che sys.argv è una stringa codificata in qualche codifica locale, anziché Unicode. Come posso leggere la riga di comando in Unicode completo?
Esempio di codice: 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)
Sul mio PC configurato per la pagina di codice giapponese, ottengo:
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>
Quella Shift-JIS codificato credo, e "funziona" per quel nome di file. Ma si rompe per i nomi di file con caratteri che non sono nel carattere Shift-JIS set-la chiamata finale "aperto" fallisce:
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'
Nota-sto parlando Python 2.x, non Python 3.0. Ho scoperto che Python 3.0 dà sys.argv
come proprio Unicode. Ma è un po 'ancora presto per passare a Python 3.0 (a causa della mancanza di supporto delle librerie terze parti).
Aggiornamento:
A poche risposte hanno detto che dovrei decodificare in base a tutto ciò che la <=> è codificato in. Il problema di questo è che non è Unicode completo, per cui alcuni personaggi non sono rappresentabili.
Ecco il caso d'uso che mi dà dolore: ho abilitato drag-and-drop dei file su file .py in Esplora risorse . Ho i nomi di file con tutti i tipi di personaggi, tra cui alcuni non nella pagina di codice predefinita del sistema. Il mio script Python non ottenere il giusto nomi di file Unicode passati ad esso tramite sys.argv in tutti i casi, quando i personaggi non sono rappresentabili nella codifica tabella codici corrente.
Non è certamente un po 'API di Windows per leggere la riga di comando con piena Unicode (e Python 3.0 lo fa). Suppongo che l'interprete Python 2.x non lo utilizza.
Soluzione
Ecco una soluzione che è proprio quello che sto cercando, facendo una chiamata alla funzione di Windows GetCommandLineArgvW
:
Get sys.argv con caratteri Unicode in Windows (da ActiveState)
Ma ho fatto diversi cambiamenti, per semplificare il suo utilizzo e gestire meglio alcuni usi. Ecco quello che io uso:
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()
Ora, il modo in cui lo uso è semplicemente quello di fare:
import sys
import win32_unicode_argv
e da allora in poi, sys.argv
è una lista di stringhe Unicode. Il modulo di Python optparse
sembra felice di analizzarlo, che è grande.
Altri suggerimenti
Si occupano di codifiche è molto confuso.
I credo se i dati inputing tramite la riga di comando che si codificare i dati come ciò che la codifica del sistema è e non è Unicode. (Anche copia / incolla dovrebbe fare questo)
Così dovrebbe essere corretto per decodificare in Unicode utilizzando la codifica di sistema:
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())
eseguendo il seguente output: Prompt> python myargv.py "PC · ソ フ ト 申請書 08.09.24.txt"
PC・ソフト申請書08.09.24.txt
<type 'str'>
<type 'unicode'>
PC・ソフト申請書08.09.24.txt
<type 'unicode'>
?日本語
Se il "PC · ソ フ ト 申請書 08.09.24.txt" contenuto del testo, "日本語". (I codificato il file come utf8 utilizzando Blocco note di Windows, sono un po 'perplesso sul motivo per cui c'è un '?' Nell'inizio durante la stampa. Qualcosa a che fare con il modo di risparmiare notepad utf8?)
Il metodo stringhe 'decodificare' o unicode () integrato può essere utilizzato per convertire una codifica in unicode.
unicode_str = utf8_str.decode('utf8')
unicode_str = unicode(utf8_str, 'utf8')
Inoltre, se il trattare con i file codificati si consiglia di utilizzare la funzione codecs.open () al posto del built-in open (). Esso consente di definire la codifica del file, e verrà quindi utilizzare la codifica data per decodificare in modo trasparente il contenuto in Unicode.
Così, quando si chiama content = codecs.open("myfile.txt", "r", "utf8").read()
content
sarà in unicode.
codecs.open: http://docs.python.org/library/codecs.html?#codecs .Open
Se io sono miss-capire qualcosa fatemelo sapere.
Se non l'hai già vi consiglio di leggere l'articolo di Joel su unicode e la codifica: http://www.joelonsoftware.com/articles/Unicode.html
Prova questo:
import sys
print repr(sys.argv[1].decode('UTF-8'))
Forse devi sostituire CP437
o CP1252
per UTF-8
. Si dovrebbe essere in grado di dedurre il nome della codifica corretta dalla chiave di registro HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage\OEMCP
La riga di comando potrebbe essere nella codifica di Windows. Prova la decodifica gli argomenti nei unicode
oggetti:
args = [unicode(x, "iso-8859-9") for x in sys.argv]