Wydawało mi się, że wiem wszystko o kodowaniu i Pythonie, ale dziś natknąłem się na dziwny problem: chociaż konsola jest ustawiona na stronę kodową 850 - a Python zgłasza to poprawnie - parametry umieszczone w wierszu poleceń wydają się być zakodowane na stronie kodowej 1252. Jeśli spróbuję je rozszyfrować przy pomocy sys.stdin.encoding, otrzymam błędny wynik. Jeśli założę "cp1252", ignorując raporty sys.stdout.encoding, to działa.Python, konsola i kodowanie okien (cp 850 vs cp1252)
Czy czegoś brakuje, czy jest to błąd w Pythonie? Windows? Uwaga: Używam Python 2.6.6 na Windows 7 EN, ustawienia regionalne na francuski (Szwajcaria).
W poniższym programie testowym sprawdzam, czy literały są poprawnie interpretowane i czy można je wydrukować - to działa. Ale wszystkie wartości mijam w wierszu poleceń wydaje się być zakodowane błędnie:
#!/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 ""
w nowo utworzonej konsoli, gdy uruchomiony
C:\dev>test-encoding.py abcé€
uzyskać następujący wynik
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 ]
podczas Spodziewam się, że czwarty znak ma wartość porządkową zamiast 233 (patrz strony kodowe 850 i 1252).
Uwagi: wartość 128 symbolu euro jest zagadką - ponieważ cp850 jej nie ma. W przeciwnym razie '?' są oczekiwane - cp850 nie może drukować znaków i użyłem "zamień" w konwersjach.
Jeśli zmienić stronę kodową konsoli do 1252 roku wydając chcp 1252
i uruchomić to samo polecenie, I (prawidłowo) uzyskać
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
Jakieś pomysły co mi brakuje?
Edytuj 1: Właśnie sprawdziłem, czytając sys.stdin. Działa to zgodnie z oczekiwaniami: w cp850 wpisanie "é" daje wartość porządkową równą 130. Tak więc problem dotyczy tylko wiersza poleceń. Czy linia poleceń jest traktowana inaczej niż standardowe wejście?
Edycja 2: Wygląda na to, że miałem złe słowa kluczowe. Znalazłem inny bardzo bliski temat na SO: Read Unicode characters from command-line arguments in Python 2.x on Windows. Nadal, jeśli linia poleceń nie jest zakodowana tak jak sys.stdin, a ponieważ sys.getdefaultencoding() zgłasza 'ascii', wydaje się, że nie ma możliwości poznania jej faktycznego kodowania. Uważam, że odpowiedź przy użyciu rozszerzeń Win32 jest dość hackowata.
Dla Linuksa zwykle 'locale.getpreferredencoding()' lub, po użyciu 'locale.setlocale()' - 'locale.getlocale() [1]' daje odpowiednie kodowanie dla konsoli i dostępu do środowiska. Chociaż zakodowany na stałe kod UTF-8 jest często wystarczająco dobry dla większości nowoczesnych systemów (więc jest to najlepsza wartość powrotna). –