Pensavo di sapere tutto sulle codifiche e su Python, ma oggi mi sono imbattuto in uno strano problema: sebbene la console sia impostata sulla codepage 850 - e Python la riporta correttamente - i parametri che ho messo sulla riga di comando sembrano essere codificati nella code page 1252. Se provo a decodificarli con sys.stdin.encoding, ottengo il risultato sbagliato. Se presumo 'cp1252', ignorando ciò che sys.stdout.encoding segnala, funziona.Python, windows console e codifiche (cp 850 vs cp1252)
Mi manca qualcosa o si tratta di un bug in Python? Finestre ? Nota: eseguo Python 2.6.6 su Windows 7 EN, locale impostato su Francese (Svizzera).
Nel programma di test di seguito, controllo che i valori letterali siano interpretati correttamente e che possano essere stampati - questo funziona. Ma tutti i valori che passano sulla linea di comando sembrano essere codificati erroneamente:
#!/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 ""
In una console di nuova creazione, quando si esegue
C:\dev>test-encoding.py abcé€
ottengo il seguente output
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 ]
mentre Mi aspetto che il quarto carattere abbia un valore ordinale di anziché 233 (vedere le tabelle codici 850 e 1252).
Note: il valore di 128 per il simbolo dell'euro è un mistero - poiché cp850 non ce l'ha. Altrimenti, il '?' sono attesi: cp850 non può stampare i caratteri e ho usato 'replace' nelle conversioni.
Se cambio la tabella codici della console al 1252 mediante l'emissione di chcp 1252
e eseguire lo stesso comando, I (correttamente) ottengo
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
Tutte le idee che mi manca?
Modifica 1: Ho appena provato leggendo sys.stdin. Funziona come previsto: in cp850, digitando 'é' si ottiene un valore ordinale di 130. Quindi il problema riguarda solo la riga di comando. Quindi, la riga di comando è trattata in modo diverso rispetto allo standard input?
Modifica 2: Sembra che avessi le parole chiave sbagliate. Ho trovato un altro argomento molto vicino su SO: Read Unicode characters from command-line arguments in Python 2.x on Windows. Tuttavia, se la riga di comando non è codificata come sys.stdin, e poiché sys.getdefaultencoding() riporta 'ascii', sembra che non ci sia modo di conoscere la sua effettiva codifica. Trovo la risposta usando le estensioni win32 piuttosto hacky.
Per Linux in genere 'locale.getpreferredencoding()' o, dopo aver usato 'locale.setlocale()' - 'locale.getlocale() [1]' fornisce la codifica corretta per l'accesso alla console e all'ambiente. Sebbene, l'UTF-8 hardcoded sia spesso abbastanza buono per la maggior parte dei sistemi moderni (quindi è il miglior valore di fallback). –