Python, консоль Windows и кодировки (cp 850 vs cp1252)

Я думал, что знаю все о кодировках и Python, но сегодня я столкнулся со странной проблемой: хотя консоль настроена на кодовую страницу 850 - и Python сообщает об этом правильно - параметры I помещенные в командную строку кажутся закодированными на кодовой странице 1252. Если я попытаюсь декодировать их с помощью sys.stdin.encoding, я получу неправильный результат. Если я предполагаю cp1252, игнорируя то, что сообщает sys.stdout.encoding, это работает.

Я что-то упускаю или это ошибка Python? Windows? Примечание. Я использую Python 2.6.6 в Windows 7 EN, установлен французский язык (Швейцария).

В приведенной ниже тестовой программе я проверяю, правильно ли интерпретируются литералы и их можно распечатать - это работает. Но все значения, которые я передаю в командной строке, кажутся закодированными неправильно:

#!/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 ""

Во вновь созданной консоли при запуске

C:\dev>test-encoding.py abcé€

я получаю следующий результат

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 ]

, в то время как я ожидал бы, что 4-й символ будет иметь порядковое значение 130 вместо 233 (см. Кодовые страницы 850 и 1252 ).

Примечания: значение 128 для символа евро остается загадкой, поскольку в cp850 его нет. В противном случае "?" ожидаются - cp850 не может печатать символы, и я использовал «заменить» в преобразованиях.

Если я изменю кодовую страницу консоли на 1252, введя chcp 1252 и запустив ту же команду, я (правильно) получу

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

Есть идеи, что мне не хватает?

Редактировать 1: Я только что проверил, прочитав sys.stdin. Это работает, как и ожидалось: в cp850 ввод «é» приводит к порядковому номеру 130. Таким образом, проблема действительно только в командной строке. Итак, обрабатывается ли командная строка иначе, чем стандартный ввод?

Редактировать 2: Кажется, у меня были неправильные ключевые слова. Я нашел еще одну очень близкую тему по SO: Чтение символов Unicode из аргументов командной строки в Python 2.x в Windows . Тем не менее, если командная строка не закодирована, как sys.stdin, и поскольку sys.getdefaultencoding () сообщает ascii, похоже, нет способа узнать ее фактическую кодировку. Я считаю, что использование расширений win32 является довольно хакерским.

16
задан Community 23 May 2017 в 12:09
поделиться