2009-09-24 2 views
16

Предположим на мгновение, что нельзя использовать print (и таким образом пользоваться преимуществами автоматического обнаружения кодировки). Так что это оставляет нас с sys.stdout. Однако sys.stdout настолько тупой, как not do any sensible encoding.Написание строк юникода через sys.stdout в Python

Теперь один читает вики-страницу Python PrintFails и идет попробовать следующий код:

$ python -c 'import sys, codecs, locale; print str(sys.stdout.encoding); \ 
    sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout); 

Однако это тоже не работает (по крайней мере, на Mac). Слишком понятно, почему:

>>> import locale 
>>> locale.getpreferredencoding() 
'mac-roman' 
>>> sys.stdout.encoding 
'UTF-8' 

(UTF-8 - это то, что понимает терминал).

Так один изменяет вышеприведенный код:

$ python -c 'import sys, codecs, locale; print str(sys.stdout.encoding); \ 
    sys.stdout = codecs.getwriter(sys.stdout.encoding)(sys.stdout); 

И теперь Юникода строки надлежащим образом отправлены sys.stdout и, следовательно, правильно напечатаны на терминале (sys.stdout присоединен терминал).

Правильно ли это написать строки Unicode в sys.stdout или я должен делать что-то еще?

EDIT: иногда - скажем, когда перенаправив вывод less - sys.stdout.encoding будет None. в этом случае вышеуказанный код не сработает.

+0

s/my/1/для консистенции – icedwater

ответ

3

Мне непонятно, почему вы не сможете печатать; но, полагая, да, подход выглядит для меня правильным.

+1

Одна из причин, по которым я не могу использовать 'print', - это избежать лишних пробелов' print'. Посмотрите на использование 'sys.stdout' здесь: http://stackoverflow.com/questions/1396820/apt-like-column-output-python-library/1397382#1397382 –

+3

Вы можете создать полные строки, а затем распечатать их. –

+0

Bravo! Да, в этом случае я могу использовать 'print' –

10

Лучшая идея - проверить, если вы напрямую подключены к терминалу. Если да, используйте кодировку терминала. В противном случае используйте предпочтительную кодировку системы.

if sys.stdout.isatty(): 
    default_encoding = sys.stdout.encoding 
else: 
    default_encoding = locale.getpreferredencoding() 

Также очень важно всегда указывать пользователю какую кодировку она хочет. Обычно я делаю это опцией командной строки (например, -e ENCODING) и разбираю ее с модулем optparse.

Другая полезная вещь: не перезаписать sys.stdout с автоматическим кодировщиком. Создайте свой кодер и используйте его, но оставьте только sys.stdout. Вы можете импортировать сторонние библиотеки, которые записывают закодированные байты непосредственно в sys.stdout.

8

Существует необязательная переменная окружения «PYTHONIOENCODING», которая может быть установлена ​​на желаемую кодировку по умолчанию. Это был бы один из способов захвата желаемой пользователем кодировки способом, совместимым со всем Python. Он похоронен в руководстве Python here.

27
export PYTHONIOENCODING=utf-8 

будет выполнять эту работу, но не может установить ее на самом python ...

, что мы можем сделать, это проверить, если не устанавливать и сообщить пользователю, чтобы установить его перед скриптом вызова с:

if __name__ == '__main__': 
    if (sys.stdout.encoding is None): 
     print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout." 
     exit(1) 
+0

Большое спасибо, работает для меня. – Kino

6

Это то, что я делаю в моем приложении:

sys.stdout.write(s.encode('utf-8'))

Это точная противоположность фикс для чтения UTF-8 имен из ARGV:

for file in sys.argv[1:]: 
    file = file.decode('utf-8') 

Это очень уродливое (IMHO), поскольку оно заставляет вас работать с UTF-8 .., что является нормой на Linux/Mac, но не на окнах ... Работает для меня в любом случае :)