2009-05-11 23 views
26

Quiero que mi script Python pueda leer argumentos de línea de comandos Unicode en Windows. Pero parece que sys.argv es una cadena codificada en alguna codificación local, en lugar de Unicode. ¿Cómo puedo leer la línea de comando en Unicode completo?Leer caracteres Unicode desde argumentos de línea de comandos en Python 2.x en Windows

código

Ejemplo: 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) 

En mi PC establecido para la página de códigos japoneses, me sale:

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> 

de ese Shift-JIS codificado creo, y "funciona" para que nombre del archivo. Pero se rompe para nombres de archivo con caracteres que no están en el carácter Shift-JIS falla puesta a la final de la llamada "abierta":

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-estoy hablando de Python 2.x, no Python 3.0. Descubrí que Python 3.0 da sys.argv como Unicode adecuado. Pero aún es un poco pronto para la transición a Python 3.0 (debido a la falta de soporte de biblioteca de terceros).

Actualización:

Algunas respuestas han dicho que debería decodificar de acuerdo a lo que el sys.argv está codificada en el problema con esto es que no es Unicode completo, por lo que algunos caracteres no son representables..

Aquí está el caso de uso que me da pena: tengo enabled drag-and-drop of files onto .py files in Windows Explorer. Tengo nombres de archivo con todo tipo de caracteres, incluidos algunos que no están en la página de códigos predeterminados del sistema. La secuencia de comandos de My Python no obtiene los nombres correctos de los archivos Unicode pasados ​​a través de sys.argv en todos los casos, cuando los caracteres no son representables en la codificación de la página de códigos actual.

Ciertamente, hay algunas API de Windows para leer la línea de comandos con Unicode completo (y Python 3.0 lo hace). Supongo que el intérprete de Python 2.x no lo está usando.

+0

¿Utiliza Windows japonés fuentes de trama en la consola por defecto? Esto probablemente limitaría la visualización de caracteres en la página de códigos de Windows-932. Consulte http://support.microsoft.com/kb/Q99795 (este es un problema separado para leer los argumentos, pero puede tener alguna incidencia) – McDowell

+0

Compruebe esta pregunta hecha aquí en Stack Overflow, debe proporcionar la respuesta a su pregunta: http://stackoverflow.com/questions/477061/how-to-read-unicode-input-and-compare-unicode-strings-in-python – AlbertoPL

+0

Sí, parece ser un duplicado exacto. –

Respuesta

27

Aquí es una solución que es justo lo que estoy buscando, hacer una llamada a la función de Windows GetCommandLineArgvW:
Get sys.argv with Unicode characters under Windows (de ActiveState)

Pero he realizado varios cambios para simplificar su uso y manejar mejor ciertos usos.Esto es lo que yo 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() 

Ahora, la forma en que lo uso es simplemente hacer:

import sys 
import win32_unicode_argv 

ya partir de entonces, sys.argv es una lista de Unicode instrumentos de cuerda. El módulo Python optparse parece feliz de analizarlo, lo cual es genial.

+0

Sí, eso funcionará. Deshazte de ".encode ('utf-8')" al final –

+0

Este fragmento de código no funciona para mí cuando arrastro y suelto el archivo en el archivo py. Sin embargo, este código funciona cuando escribo el nombre del archivo en el símbolo del sistema. Y escribí un programa en C++ para llamar a GetCommandLineW, el programa puede mostrar el nombre del archivo correctamente si arrastro y coloco el archivo en el programa. – franziga

+0

@franziga: ¿Qué significa "no funciona" en específico? Es necesario [habilitar arrastrar y soltar en archivos de Python] (http://stackoverflow.com/q/142844/60075). Ha pasado un tiempo (y una compañía diferente) desde que hice esto, pero creo que debo haber habilitado nombres de archivo largos. –

0

La línea de comando puede estar en la codificación de Windows. Trate de decodificar los argumentos en unicode objetos:

args = [unicode(x, "iso-8859-9") for x in sys.argv] 
+0

sys.args -> sys.argv – pts

+0

Gracias, corregido .... –

+2

-1 "iso-8859-9" NO es una codificación de Windows. Acabas de empeorar el problema. –

2

Prueba esto:

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

Tal vez tenga que sustituir CP437 o CP1252 para UTF-8. Usted debe ser capaz de inferir el nombre de una correcta codificación de la clave de registro HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage\OEMCP

10

El manejo de las codificaciones es muy confuso.

I cree si sus datos de entrada a través de la línea de comandos codificará los datos como cualquiera que sea la codificación de su sistema y no es unicode. (Incluso copiar/pegar debe hacer esto)

lo tanto, debe ser correcto para decodificar en Unicode mediante el sistema de codificación:

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

la ejecución del siguiente salida será: Prompt> pitón myargv.py "· PCソ フ ト 申請書 08.09.24.txt"

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

Cuando el "PC · ソ フ ト 申請書 08.09.24.txt" que figura el texto, "日本語". (Codifiqué el archivo como utf8 usando el bloc de notas de Windows, estoy un poco perplejo sobre por qué hay un '?' En el comienzo al imprimir. Algo relacionado con cómo el bloc de notas guarda utf8?)

Decodificación de cadenas 'method o el unicode() incorporado se puede utilizar para convertir una codificación en Unicode.

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

Además, si su trato con los archivos codificados es posible que desee utilizar la función codecs.open() en lugar de la incorporada en abierto(). Le permite definir la codificación del archivo, y luego usará la codificación dada para decodificar de forma transparente el contenido a unicode.

Por lo tanto, cuando llame al content = codecs.open("myfile.txt", "r", "utf8").read()content estará en Unicode.

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

Si soy miss-comprensión algo por favor hágamelo saber.

Si no lo ha hecho Recomiendo leer el artículo de Joel en Unicode y codificación: http://www.joelonsoftware.com/articles/Unicode.html

Cuestiones relacionadas