Я использую этот код для получения стандартного вывода из внешней программы:
>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
Метод communication () возвращает массив байтов:
>>> command_stdout
b'total 0\n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file1\n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file2\n'
Тем не менее, я хотел бы работать с выводом в виде обычной строки Python. Чтобы я мог напечатать это так:
>>> print(command_stdout)
-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file1
-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file2
Я думал, что для этого предназначен метод binascii.b2a_qp () , но когда я попробовал его, я снова получил тот же байтовый массив:
>>> binascii.b2a_qp(command_stdout)
b'total 0\n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file1\n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file2\n'
Как преобразовать значение байтов обратно в строку? Я имею в виду, используя «батареи» вместо того, чтобы делать это вручную. И я бы хотел, чтобы с Python 3 все было в порядке.
python
string
python-3.x
Томас Седович
источник
источник
str(text_bytes)
работает? Это кажется странным для меня.str(text_bytes)
не могу указать кодировку. В зависимости от того, что в text_bytes,text_bytes.decode('cp1250
) `может привести к совсем другой строкеtext_bytes.decode('utf-8')
.str
функция больше не преобразуется в реальную строку. Нужно сказать кодировку явно, по какой-то причине мне лень читать, почему. Просто преобразуйте егоutf-8
и посмотрите, работает ли ваш код. Напримерvar = var.decode('utf-8')
unicode_text = str(bytestring, character_encoding)
работает должным образом на Python 3. Хотяunicode_text = bytestring.decode(character_encoding)
предпочтительнее избегать путаницы с тем,str(bytes_obj)
чтоbytes_obj
вместо текстового представления создается текстовое представление,str(b'\xb6', 'cp1252') == b'\xb6'.decode('cp1252') == '¶'
аstr(b'\xb6') == "b'\\xb6'" == repr(b'\xb6') != '¶'
Ответы:
Вам нужно декодировать объект bytes, чтобы получить строку:
источник
"windows-1252"
ненадежно (например, для других языковых версий Windows), не лучше ли будет использоватьsys.stdout.encoding
?b"\x80\x02\x03".decode("utf-8")
->UnicodeDecodeError: 'utf8' codec can't decode byte 0x80 in position 0: invalid start byte
.utf-8
преобразование, скорее всего, не удастся. Вместо этого смотрите ответ @techtonik (ниже) stackoverflow.com/a/27527728/198536Вам необходимо декодировать строку байтов и превратить ее в символьную строку (Unicode).
На питоне 2
или
На питоне 3
или
источник
variable = b'hello'
, тоunicode_text = variable.decode(character_encoding)
Я думаю, что так легко
источник
bytes([112, 52, 52])
- кстати, байты - это плохое имя для локальной переменной именно потому, что онаЕсли вы не знаете кодировку, то для чтения двоичного ввода в строку в Python 3 и Python 2-совместимом способе используйте древнюю кодировку MS-DOS CP437 :
Поскольку кодировка неизвестна, ожидайте, что неанглийские символы будут переводиться в символы
cp437
(английские символы не переводятся, поскольку они совпадают в большинстве однобайтовых кодировок и UTF-8).Декодирование произвольного двоичного ввода в UTF-8 небезопасно, потому что вы можете получить это:
То же самое относится и к тому
latin-1
, что было популярно (по умолчанию?) Для Python 2. Смотрите недостающие точки в Layout Codepage - именно там Python задыхается от дурной славыordinal not in range
.ОБНОВЛЕНИЕ 20150604 : Ходят слухи, что в Python 3 есть
surrogateescape
стратегия ошибок для кодирования содержимого в двоичные данные без потери данных и сбоев, но для этого необходимы тесты преобразования[binary] -> [str] -> [binary]
для проверки как производительности, так и надежности.ОБНОВЛЕНИЕ 20170116 : Благодаря комментарию Nearoo - также есть возможность сократить все неизвестные байты с помощью
backslashreplace
обработчика ошибок. Это работает только для Python 3, поэтому даже при таком обходном пути вы все равно получите противоречивый вывод из разных версий Python:См . Поддержку Unicode Python для деталей.
ОБНОВЛЕНИЕ 20170119 : Я решил реализовать декодирование с косой чертой, которое работает как для Python 2, так и для Python 3. Оно должно быть медленнее, чем
cp437
решение, но оно должно давать идентичные результаты для каждой версии Python.источник
b'\x00\x01\xffsd'.decode('utf-8', 'ignore')
в Python 3.b'\x80abc'.decode("utf-8", "backslashreplace")
приведет к'\\x80abc'
. Эта информация была взята со страницы документации Unicode, которая, кажется, была обновлена с момента написания этого ответа.В Python 3 кодировкой по умолчанию является
"utf-8"
, так что вы можете напрямую использовать:что эквивалентно
С другой стороны, в Python 2 кодировка по умолчанию соответствует строковому кодированию по умолчанию. Таким образом, вы должны использовать:
где
encoding
кодировка, которую вы хотите.Примечание: поддержка аргументов ключевых слов была добавлена в Python 2.7.
источник
Я думаю, что вы действительно хотите это:
Ответ Аарона был верным, за исключением того, что вам нужно знать, какую кодировку использовать. И я считаю, что Windows использует «Windows-1252». Это будет иметь значение, только если у вас есть какие-то необычные (не ASCII) символы в вашем контенте, но тогда это будет иметь значение.
Кстати, тот факт, что это имеет значение, является причиной того, что Python перешел на использование двух разных типов для двоичных и текстовых данных: он не может магически преобразовывать между ними, потому что он не знает кодировку, пока вы не скажете это! Единственный способ узнать это - прочитать документацию по Windows (или прочитать ее здесь).
источник
open()
функция для текстовых потоков или,Popen()
если вы ее передадитеuniversal_newlines=True
, волшебным образом решите для вас кодировку символов (locale.getpreferredencoding(False)
в Python 3.3+).'latin-1'
это дословное кодирование со всеми установленными кодовыми точками, так что вы можете использовать его для эффективного чтения байтовой строки в любой тип строки, поддерживаемый вашим Python (так дословно на Python 2, в Unicode для Python 3).'latin-1'
хороший способ получить моджибаке. Также в Windows есть волшебная замена: на удивление трудно передавать данные из одного процесса в другой без изменений, напримерdir
:\xb6
->\x14
(пример в конце моего ответа)Установите для universal_newlines значение True, т.е.
источник
text=True
вместоuniversal_newlines=True
.Хотя ответ @Aaron Maenpaa просто работает, недавно пользователь спросил :
Ты можешь использовать:
decode()
имеет стандартный аргумент :источник
.decode()
это'utf-8'
может привести к сбою (выходные данные команды могут использовать другую кодировку символов или даже возвращать некодируемую последовательность байтов). Хотя, если ввод ascii (подмножество utf-8), то.decode()
работает.Чтобы интерпретировать последовательность байтов как текст, вы должны знать соответствующую кодировку символов:
Пример:
ls
Команда может выдавать вывод, который не может быть интерпретирован как текст. Имена файлов в Unix могут быть любой последовательностью байтов, кроме косой чертыb'/'
и нуляb'\0'
:Попытка расшифровать такой суп, используя кодировку utf-8, повышает
UnicodeDecodeError
.Это может быть хуже. Декодирование может произойти сбой без вывода сообщений и может привести к созданию mojibake, если вы используете неправильную несовместимую кодировку:
Данные повреждены, но ваша программа не знает, что произошел сбой.
В общем, какая кодировка символов не используется в самой последовательности байтов. Вы должны сообщить эту информацию вне группы. Некоторые результаты более вероятны, чем другие, и поэтому
chardet
существует модуль, который может угадать кодировку символов. Один скрипт Python может использовать несколько кодировок символов в разных местах.ls
вывод может быть преобразован в строку Python с помощьюos.fsdecode()
функции, которая успешно выполняется даже для не кодируемых имен файлов ( в Unix используетсяsys.getfilesystemencoding()
иsurrogateescape
обработчик ошибок):Чтобы получить оригинальные байты, вы можете использовать
os.fsencode()
.Если вы передаете
universal_newlines=True
параметр, тоsubprocess
используетеlocale.getpreferredencoding(False)
для декодирования байтов, например, это может бытьcp1252
в Windows.Чтобы декодировать поток байтов на лету,
io.TextIOWrapper()
можно использовать: пример .Разные команды могут использовать разные кодировки для вывода, например,
dir
внутренняя команда (cmd
) может использовать cp437. Чтобы декодировать его вывод, вы можете явно передать кодировку (Python 3.6+):Имена файлов могут отличаться от
os.listdir()
(которые используют Windows Unicode API), например,'\xb6'
могут быть заменены'\x14'
на карты кодека -Python cp437b'\x14'
для управления символом U + 0014 вместо U + 00B6 (¶). Чтобы поддержать имена файлов с произвольными символами Unicode, см. Декодирование вывода PowerShell, возможно, содержащее символы не-ASCII Unicode в строку Pythonисточник
Поскольку этот вопрос на самом деле касается
subprocess
вывода, у вас есть более прямой подход, так как онPopen
принимает ключевое слово кодирования (в Python 3.6+):Общий ответ для других пользователей - декодировать байты в текст:
Без аргументов
sys.getdefaultencoding()
будет использоваться. Если ваших данных нетsys.getdefaultencoding()
, то вы должны явно указать кодировку вdecode
вызове:источник
text=True
к декодированию stdin, stdout и stderr, используя заданную кодировку (если установлена) или системное значение по умолчанию в противном случае.Popen(['ls', '-l'], stdout=PIPE, text=True)
,ls
Вывод декодирования с использованиемutf-8
кодирования может быть неудачным (см. Пример в моем ответе от 2016 года ).encoding
параметр, тоtext
параметр игнорируется.Если вы должны получить следующее, попробовав
decode()
:Вы также можете указать тип кодировки прямо в приведении:
источник
При работе с данными из систем Windows (с
\r\n
окончаниями строк) мой ответ:Почему? Попробуйте это с многострочным Input.txt:
Все окончания вашей строки будут удвоены (до
\r\r\n
), что приведет к лишним пустым строкам. Функции чтения текста в Python обычно нормализуют окончания строк, поэтому используются только строки\n
. Если вы получаете двоичные данные из системы Windows, у Python нет шансов сделать это. Таким образом,будет копировать ваш оригинальный файл.
источник
.replace("\r\n", "\n")
так долго искал дополнение. Это ответ, если вы хотите правильно отобразить HTML.Я сделал функцию для очистки списка
источник
.strip
,.replace
,.encode
, и т.д. вызовы в одном списке понимание и только итерация по списку раз вместо Перебор него пять раз.Для Python 3 это гораздо более безопасный и Pythonic подход для преобразования
byte
вstring
:Вывод:
источник
byte_to_str
", что означает, что она возвратит str, но она только печатает преобразованное значение и выводит сообщение об ошибке, если она не срабатывает (но не вызывает исключение). Этот подход также неуместный и запутываетbytes.decode
решение, которое вы предоставили.От sys - Системные параметры и функции :
Для записи или чтения двоичных данных из / в стандартные потоки используйте базовый двоичный буфер. Например, чтобы записать байты в стандартный вывод, используйте
sys.stdout.buffer.write(b'abc')
.источник
bytes
значения.источник
Для вашего конкретного случая «запустить команду оболочки и получить ее вывод в виде текста вместо байтов», в Python 3.7 вы должны использовать
subprocess.run
и передатьtext=True
(а такжеcapture_output=True
захватывать вывод)text
Раньше вызывалсяuniversal_newlines
и был изменен (ну, псевдоним) в Python 3.7. Если вы хотите поддерживать версии Python до 3.7,universal_newlines=True
вместоtext=True
источник
Если вы хотите преобразовать любые байты, а не просто строку, преобразованную в байты:
Это не очень эффективно, однако. Это превратит изображение 2 МБ в 9 МБ.
источник
попробуй это
источник