Вывести строку в кодировке Юникод в консоль ОК, но происходит сбой при перенаправлении в файл. Как исправить?

У меня есть Python 2.7.1 на упрощенной китайской версии Windows XP, и у меня есть такая программа (windows_prn_utf8.py):

#!/usr/bin/env python
# -*- coding: utf8 -*-

print unicode('\xE7\x94\xB5', 'utf8')

Если я запускаю его на консоли Windows CMD, он выводит правильный китайский символ '电'; однако, если я пытаюсь перенаправить вывод команды в файл. Я получил ошибку.

D:\Temp>windows_prn_utf8.py > 1.txt
Traceback (most recent call last):
  File "D:\Temp\windows_prn_utf8.py", line 4, in <module>
    print unicode('\xE7\x94\xB5', 'utf8')
UnicodeEncodeError: 'ascii' codec can't encode character u'\u7535' in position 0: ordinal not in range(128)

Я понимаю, что здесь отсутствует ссылка. Должен быть способ определить, в случае генерирования 1.txt, должен ли кодировщик Unicode в 1.txt кодироваться в utf-8 или codepage-936 или в других кодировках.

Тогда как это исправить? Я предпочитаю иметь кодировку utf-8 в 1.txt . Спасибо.

4 ответа

Решение

Задавать PYTHONIOENCODING переменная среды

SET PYTHONIOENCODING=cp936
windows_prn_utf8.py > 1.txt

Кажется, что это было решено, но я думаю, что немного больше деталей помогут объяснить эту актуальную проблему.

UTF8 в unicode('\xE7\x94\xB5', 'utf8') говорит интерпретатору, как декодировать 3 байта, которые вы предоставляете в другом аргументе, для внутреннего представления символа как объекта Юникода:

In [6]: uobj = unicode('\xe7\x94\xb5','utf8')

In [7]: uobj
Out[7]: u'\u7535'

Другим примером было бы создание того же символа из его представления utf-16 (именно это Python отображает по умолчанию и показывает в Out[7] строка выше):

In [8]: uobj = unicode('\x35\x75','utf16')

In [9]: uobj
Out[9]: u'\u7535'

В вашем примере после создания объекта он становится аргументом для print который пытается записать его в стандартный формат (консольное окно, перенаправление в файл и т. д.). Сложность в том, что print перед записью необходимо перекодировать этот объект в поток байтов. Похоже, что в вашем случае кодировка, используемая по умолчанию, была ACSII, которая не может представлять этот символ.

(Если консоль попытается отобразить символы, они будут повторно декодированы и заменены в окне соответствующими символами шрифта - вот почему ваш вывод и консоль должны "говорить" в одной и той же кодировке.)

Из того, что я видел, cmd.exe в Windows довольно запутанно, когда дело доходит до кодирования символов, но в других ОС я делаю явное кодирование байтов перед печатью / записью их с помощью объекта Unicode. encode функция. Это возвращает закодированную последовательность байтов, сохраненную в str объект:

In [10]: sobj = uobj.encode('utf8')

In [11]: type(sobj)
Out[11]: str

In [12]: sobj
Out[12]: '\xe7\x94\xb5'

In [13]: print sobj
电

Теперь, когда print дается str вместо unicodeне нужно ничего кодировать. В моем случае мой терминал декодировал utf8, и его шрифт содержал именно этот символ, поэтому он правильно отображался на моем экране (и, надеюсь, прямо сейчас в вашем браузере).

Вы можете закодировать его в utf-8, прежде чем записать его в файл.

f.write("电".encode("utf8"))

Используйте codecs.open(имя файла, кодировка) вместо open (имя файла) и запишите файл с помощью python.

Другие вопросы по тегам