Подпроцесс Python отображает литерал Юникода

Я знаю, что такие вопросы задавались раньше. Но я не нахожу решения.

Я хочу использовать литерал Unicode, определенный в моем файле Python, с модулем подпроцесса. Но я не получаю результаты, которые мне нужны. Например, следующий код

# -*- coding: utf-8 -*-
import sys
import codecs
import subprocess
cmd = ['echo', u'你好']
new_cmd = []
for c in cmd:
    if isinstance(c,unicode):
        c = c.encode('utf-8')
    new_cmd.append(c)
subprocess.call(new_cmd)

распечатывает

你好

Если я изменю код на

# -*- coding: utf-8 -*-
import sys
import codecs
import subprocess
cmd = ['echo', u'你好']
new_cmd = []
for c in cmd:
    if isinstance(c,unicode):
        c = c.encode(sys.getfilesystemencoding())
    new_cmd.append(c)
subprocess.call(new_cmd)

Я получаю следующее

??

На этом этапе я могу только предположить, что я неоднократно совершаю простую ошибку. Но мне трудно понять, что это такое. Как я могу получить эхо, чтобы распечатать следующее при вызове через подпроцесс Python

你好

Редактировать:

Версия Python 2.7. Я работаю на Windows 8, но я бы хотел, чтобы решение не зависело от платформы.

2 ответа

Решение

Вывод: обратите внимание на кодировки символов (здесь есть три различных кодировки символов). Используйте Python 3, если вам нужна поддержка переносимого Unicode (передавайте аргументы как Unicode, не кодируйте их) или убедитесь, что данные могут быть представлены с использованием текущих кодировок символов из среды (кодирование с использованием sys.getfilesystemencoding() на Python 2, как вы делаете во втором примере кода).


Первый пример кода неверен. Эффект такой же, как (запустить его в режиме IDLE - py -3 -midlelib):

>>> print(u'你好'.encode('utf-8').decode('mbcs')) #XXX DON'T DO IT!
你好

где mbcs кодек использует вашу кодовую страницу Windows ANSI (обычно: cp1252 кодировка символов - может отличаться, например, cp1251 на русской винде).

Python 2 использует CreateProcess макросы для запуска подпроцесса, эквивалентного CreateProcessA функционировать там. CreateProcessA интерпретирует входные байты как закодированные с использованием вашей кодировки ANSI Windows. Он не связан с кодировкой исходного кода Python (в вашем случае utf-8).

Ожидается, что вы получите mojibake, если вы используете неправильную кодировку.


Ваш второй пример кода должен работать, если вводимые символы могут быть представлены с использованием кодовой страницы Windows, такой как cp1252 (чтобы включить кодирование из Unicode в байты), и если echo использует Unicode API для печати на консоли Windows, такой как WriteConsoleW() (см. пакет Python 3 win-unicode-console -- это позволяет print(u'你好') независимо от того, какой у вас chcp ("OEM"), если шрифт в консоли поддерживает символы) или символы могут быть представлены с использованием кодовой страницы OEM (используется cmd.exe) такие как cp437 (бежать chcp узнать твои). ?? вопросительные знаки указывают на то, что 你好 не может быть представлен с использованием вашей консольной кодировки.

Для поддержки произвольных аргументов Unicode (включая символы, которые нельзя представить с использованием кодовых страниц Windows ("ANSI") или MS-DOS (OEM)), вам необходимо CreateProcessW функция (которая используется в Python 3). Посмотрите имена файлов Unicode в Windows с Python и subprocess.Popen ().

Ваша первая попытка была лучшей.

Вы фактически конвертировали 2 символа Юникод u'你好' (или же u'\u4f60\u597d'б) в UTF8 все что дается b'\xe4\xbd\xa0\xe5\xa5\xbd',

Вы можете управлять им в IDLE, который полностью поддерживает Unicode и где b'\xe4\xbd\xa0\xe5\xa5\xbd'.decode('utf-8') отдает 你好, Другой способ управления им - перенаправить вывод скрипта в файл и открыть его с помощью редактора, совместимого с UTF-8: там вы снова увидите то, что хотите.

Но проблема в том, что консоль Windows не поддерживает полный Unicode. Это зависит от:

  • кодовая страница установлена ​​- я не знаю для Windows 8, но предыдущие версии имели плохую поддержку юникода и могли отображать только 256 символов
  • шрифт, используемый в консоли - не все шрифты имеют глифы для всех символов.

Если вы знаете кодовую страницу, которая содержит символы для ваших символов (я не знаю), вы можете попробовать вставить ее в консоль с помощью chcp и явно кодировать вашу строку Unicode к этому. Но на моем французском компьютере я не знаю, как это сделать... кроме как путем передачи текстового файла!

Как вы говорили о ConEmu, я попробовал... и он отлично работает с Python 3.4!

chcp 65001
py -3
import subprocess
cmd = ['cmd', '/c', 'echo', u'\u4f60\u597d']
subprocess.call(cmd)

дает:

你好  
0

Проблема только в cmd.exe окна!

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