Pensé que sabía todo sobre codificaciones y Python, pero hoy me encontré con un problema extraño: aunque la consola está configurada en la página de códigos 850 y Python lo informa correctamente, Los parámetros que puse en la línea de comando parecen estar codificados en la página de códigos 1252. Si intento decodificarlos con sys.stdin.encoding, obtengo el resultado incorrecto. Si asumo 'cp1252', ignorando los informes de sys.stdout.encoding, funciona.Python, consola de Windows y codificaciones (cp 850 vs cp1252)
¿Me falta algo, o es esto un error en Python? Windows? Nota: Estoy ejecutando Python 2.6.6 en Windows 7 EN, configuración regional en francés (Suiza).
En el programa de prueba a continuación, compruebo que los literales se interpretan correctamente y se pueden imprimir, esto funciona. Sin embargo, todos los valores de los que paso en la línea de comandos parecen ser codificados erróneamente:
#!/usr/bin/python
# -*- encoding: utf-8 -*-
import sys
literal_mb = 'utf-8 literal: üèéÃÂç€ÈÚ'
literal_u = u'unicode literal: üèéÃÂç€ÈÚ'
print "Testing literals"
print literal_mb.decode('utf-8').encode(sys.stdout.encoding,'replace')
print literal_u.encode(sys.stdout.encoding,'replace')
print "Testing arguments (stdin/out encodings:",sys.stdin.encoding,"/",sys.stdout.encoding,")"
for i in range(1,len(sys.argv)):
arg = sys.argv[i]
print "arg",i,":",arg
for ch in arg:
print " ",ch,"->",ord(ch),
if ord(ch)>=128 and sys.stdin.encoding == 'cp850':
print "<-",ch.decode('cp1252').encode(sys.stdout.encoding,'replace'),"[assuming input was actually cp1252 ]"
else:
print ""
En una consola de nueva creación, cuando se ejecuta
C:\dev>test-encoding.py abcé€
Me da la siguiente salida
Testing literals
utf-8 literal: üèéÃÂç?ÈÚ
unicode literal: üèéÃÂç?ÈÚ
Testing arguments (stdin/out encodings: cp850/cp850)
arg 1 : abcÚÇ
a -> 97
b -> 98
c -> 99
Ú -> 233 <- é [assuming input was actually cp1252 ]
Ç -> 128 <- ? [assuming input was actually cp1252 ]
mientras Esperaría que el 4to carácter tenga un valor ordinal de en vez de 233 (vea las páginas de códigos 850 y 1252).
Notas: el valor de 128 para el símbolo del euro es un misterio, ya que cp850 no lo tiene. De lo contrario, el '?' se esperan - cp850 no puede imprimir los caracteres y he usado 'reemplazar' en las conversiones.
Si cambio de la página de códigos de la consola para 1252 mediante la emisión de chcp 1252
y ejecutar el mismo comando, I (correctamente) Obtener
Testing literals
utf-8 literal: üèéÃÂç€ÈÚ
unicode literal: üèéÃÂç€ÈÚ
Testing arguments (stdin/out encodings: cp1252/cp1252)
arg 1 : abcé€
a -> 97
b -> 98
c -> 99
é -> 233
€ -> 128
Alguna idea de lo que me falta?
Edit 1: Acabo de probar leyendo sys.stdin. Esto funciona como se esperaba: en cp850, escribir 'é' da como resultado un valor ordinal de 130. Por lo tanto, el problema es realmente solo para la línea de comando. Entonces, ¿la línea de comando se trata de manera diferente a la entrada estándar?
Editar 2: Parece que tuve las palabras clave incorrectas. Encontré otro tema muy cercano en SO: Read Unicode characters from command-line arguments in Python 2.x on Windows. Aún así, si la línea de comando no está codificada como sys.stdin, y dado que sys.getdefaultencoding() informa 'ascii', parece que no hay forma de conocer su codificación real. La respuesta que uso extensiones de win32 me parece bastante hacky.
Para Linux usualmente 'locale.getpreferredencoding()' o, después de usar 'locale.setlocale()' - 'locale.getlocale() [1]' proporciona la codificación correcta para el acceso a la consola y al entorno. Sin embargo, el UTF-8 codificado a menudo es lo suficientemente bueno para la mayoría de los sistemas modernos (por lo que es el mejor valor de recuperación). –