Преобразование байтов в строку

Я использую этот код для получения стандартного вывода из внешней программы:

>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]

Метод communicate() возвращает массив байтов:

>>> 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.

Комментарии к вопросу (3)
Решение

Вам нужно декодировать объект bytes, чтобы получить строку:

>>> b"abcde"
b'abcde'

# utf-8 is used here because it is a very common encoding, but you
# need to use the encoding your data is actually in.
>>> b"abcde".decode("utf-8") 
'abcde'
Комментарии (18)

Вам нужно декодировать байтовую строку и превратить ее в символьную строку (Unicode).

В Python 2

encoding = 'utf-8'
'hello'.decode(encoding)

или

unicode('hello', encoding)

На Python 3

encoding = 'utf-8'
b'hello'.decode(encoding)

или

str(b'hello', encoding)
Комментарии (0)

Я думаю, что это так легко:

bytes_data = [112, 52, 52]
"".join(map(chr, bytes_data))
>> p44
Комментарии (12)

Если вы Don'т знать кодировку, чтобы потом прочитать двоичный ввод в строку в Python 3 и Python 2 совместимым способом, используют древние МС-Дос CP437 кодировка:

PY3K = sys.version_info >= (3, 0)

lines = []
for line in stream:
    if not PY3K:
        lines.append(line)
    else:
        lines.append(line.decode('cp437'))

Потому что кодировка неизвестна, ожидать не-английские символы переводить в символы cp437 (английские символы не переводятся, поскольку они совпадают в большинстве однобайтовых кодировках и UTF-8).

Декодирование произвольных двоичных входных данных в UTF-8 является небезопасным, потому что вы можете сделать это:

>>> b'\x00\x01\xffsd'.decode('utf-8')
Traceback (most recent call last):
  File "", line 1, in 
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 2: invalid
start byte

То же самое относится к Латинская-1, который был популярен (по умолчанию?) для Python 2. Увидеть недостающие пункты в макет кодовой страницы - это где питон дроссели с печально известной порядковый номер не в диапазон.

Обновление 20150604: ходят слухи, что Python 3 имеет surrogateescape ошибка стратегии для кодирования в двоичном данных без потери данных и сбои, но для этого нужно преобразование тесты, [двоичный] -> [стр] -> [двоичный], чтобы проверить производительность и надежность.

Обновление 20170116: спасибо комментарий Nearoo - появилась возможность сократить избежать всех неизвестных байт с backslashreplace` обработчик ошибок. Это работает только для Python 3, так что даже это временное решение, вы все равно получите противоречивые выход из разных версий питона:

PY3K = sys.version_info >= (3, 0)

lines = []
for line in stream:
    if not PY3K:
        lines.append(line)
    else:
        lines.append(line.decode('utf-8', 'backslashreplace'))

См. поддержка Unicode в Python для получения подробных сведений.

Обновление 20170119: я решил реализовать Слэш побега декодирования, который работает как питон&ампер;усилитель; nbsp;2 и Python&ампер;усилитель; nbsp;3. Она должна быть медленнее, чем cp437 решение, но оно должно производить идентичные результаты на любой версии Python.

# --- preparation

import codecs

def slashescape(err):
    """ codecs error handler. err is UnicodeDecode instance. return
    a tuple with a replacement for the unencodable part of the input
    and a position where encoding should continue"""
    #print err, dir(err), err.start, err.end, err.object[:err.start]
    thebyte = err.object[err.start:err.end]
    repl = u'\\x'+hex(ord(thebyte))[2:]
    return (repl, err.end)

codecs.register_error('slashescape', slashescape)

# --- processing

stream = [b'\x80abc']

lines = []
for line in stream:
    lines.append(line.decode('utf-8', 'slashescape'))
Комментарии (8)

В Python 3, кодировку по умолчанию в "в UTF-8" в, так что вы можете напрямую использовать:

b'hello'.decode()

что эквивалентно

b'hello'.decode(encoding="utf-8")

С другой стороны, в Python 2, используется кодировка по умолчанию в строку кодировки по умолчанию. Таким образом, вы должны использовать:

b'hello'.decode(encoding)

где кодировка-это кодировка, которую вы хотите.

Примечание: в поддержку доводов сайта был добавлен в Python&ампер;усилитель; nbsp;2.7.

Комментарии (0)

Я думаю, ты действительно хочешь этого:

>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
>>> command_text = command_stdout.decode(encoding='windows-1252')

Ответ Aaron'a был правильным, за исключением того, что вам нужно знать какую кодировку использовать. И я полагаю, что Windows использует 'windows-1252'. Это будет иметь значение, только если у вас есть необычные (не ASCII) символы в вашем контенте, но тогда это будет иметь значение.

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

Комментарии (2)

Набор universal_newlines значение true, т. е.

command_stdout = Popen(['ls', '-l'], stdout=PIPE, universal_newlines=True).communicate()[0]
Комментарии (2)

В то время как @Аарон мяэнпяа: дизайн для всех'ы ответ просто работает, пользователь недавно:

Есть ли какой более простой способ? 'fhand.читать().расшифруйте("в формате ASCII" в)' [...] Он's так долго!

Вы можете использовать:

command_stdout.decode()

декодировать() имеет стандартный аргумент:

кодеки.расшифруйте(объект, кодировка='кодировка UTF-8', ошибки='жестких')

Комментарии (0)

Поскольку этот вопрос на самом деле спрашивает о подпроцесс выход, у вас есть более прямой подход, поскольку к popen принимает кодирование ключевое слово (в языке Python 3.6+):

>>> from subprocess import Popen, PIPE
>>> text = Popen(['ls', '-l'], stdout=PIPE, encoding='utf-8').communicate()[0]
>>> type(text)
str
>>> print(text)
total 0
-rw-r--r-- 1 wim badger 0 May 31 12:45 some_file.txt

Общего ответа для других пользователей - расшифруйте байт в текст:

>>> b'abcde'.decode()
'abcde'

Без аргумента, sys файла.getdefaultencoding() будет использоваться. Если ваши данные не sys файла.getdefaultencoding(), то вы должны явно указать кодировку в расшифровать вызов:

>>> b'caf\xe9'.decode('cp1250')
'café'
Комментарии (1)

Интерпретировать последовательность байтов в текст, вы должны знать соответствующие кодировки:

unicode_text = bytestring.decode(character_encoding)

Пример:

>>> b'\xc2\xb5'.decode('utf-8')
'µ'

команда ls может производить продукцию, которая может'т быть интерпретированы как текст. Имена файлов в Unix может быть любая последовательность байтов, за исключением Слэшб'/'и ноль б'\0':

>>> open(bytes(range(0x100)).translate(None, b'\0/'), 'w').close()

Пытаясь расшифровать такие байта суп, используя кодировку UTF-8 поднимает UnicodeDecodeError.

Он может быть хуже. Раскодирование могут молча отказать и произвести mojibake если вы используете неправильную несовместимые кодировки:

>>> '—'.encode('utf-8').decode('cp1252')
'—'

Если данные повреждены, но ваша программа по-прежнему не подозревая, что неудача произошло.

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


команды ls выход может быть преобразован в строку в Python с использованием ОС [.fsdecode() функции] (), что удается даже для undecodable имена файлов (он использует Сыс.getfilesystemencoding() и surrogateescape обработчик ошибок на В Unix):

import os
import subprocess

output = os.fsdecode(subprocess.check_output('ls'))

Чтобы получить исходный байт, вы можете использовать ОС.fsencode().

Если вы проходите universal_newlines=правда параметра подпроцесс использует язык.getpreferredencoding(ложные) для декодирования байтов, например, это может быть cp1252 в Windows.

Чтобы расшифровать байтовый поток на лету, Ио.TextIOWrapper() могут быть использованы: пример.

Различные команды могут использовать различные кодировки для их выход например, внутренние команды DIR `("ЦМД") может использовать cp437. Чтобы расшифровать его выход, можно пройти кодировку явно (питон 3.6+):

output = subprocess.check_output('dir', shell=True, encoding='cp437')

Имена файлов могут отличаться от операционной системы.listdir()(который использует Windows API для Юникода), например,'\хв6'можно заменить'\х14'`—питон'ы cp437 кодек карты б'\х14' контролировать символа U+0014 вместо У+00B6 (¶). Для поддержки файлов с произвольными символами Unicode, см. https://stackoverflow.com/q/33936074/4279

Комментарии (0)

Если вы должны получить следующие попытки декодировать():

AttributeError: 'ул.' объект не имеет атрибут 'расшифровать'

Вы также можете указать тип кодировки прямо в гипсе:

>>> my_byte_str
b'Hello World'

>>> str(my_byte_str, 'utf-8')
'Hello World'
Комментарии (0)

При работе с данными из систем Windows (с\R конца строки\п`), мой ответ

String = Bytes.decode("utf-8").replace("\r\n", "\n")

Почему? Попробуйте это с многолинейным Input.txt:

Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8")
open("Output.txt", "w").write(String)

Все окончания строк будет в два раза (до \р\р\н), что приводит к дополнительной пустой строки. В Python'ы, текст-прочитать функции обычно нормализовать окончаний строк, так что используем только строки \п. Если вы получаете двоичных данных из системы Windows, Python не имеют шанс сделать это. Таким образом,

Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8").replace("\r\n", "\n")
open("Output.txt", "w").write(String)

будет повторить ваш исходный файл.

Комментарии (1)

Я сделал функцию, чтобы очистить список

def cleanLists(self, lista):
    lista = [x.strip() for x in lista]
    lista = [x.replace('\n', '') for x in lista]
    lista = [x.replace('\b', '') for x in lista]
    lista = [x.encode('utf8') for x in lista]
    lista = [x.decode('utf8') for x in lista]

    return lista
Комментарии (2)

Для Python 3, это гораздо безопаснее и обновления подход конвертировать из байт в строку:

def byte_to_str(bytes_or_str):
    if isinstance(bytes_or_str, bytes): # Check if it's in bytes
        print(bytes_or_str.decode('utf-8'))
    else:
        print("Object not of byte type")

byte_to_str(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')

Выход:

total 0
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2
Комментарии (2)

С системы системы-конкретные параметры и функции:

Для записи или чтения двоичных данных из/в стандартные потоки, использование базовых двоичных буфера. Например, чтобы записать байты в файл, используйте представление sys.поток stdout.буфер.напишите(б'азбуке')`.

Комментарии (1)
def toString(string):    
    try:
        return v.decode("utf-8")
    except ValueError:
        return string

b = b'97.080.500'
s = '97.080.500'
print(toString(b))
print(toString(s))
Комментарии (2)

Если вы хотите сконвертировать байты, а не просто строку, преобразованную в байтах:

with open("bytesfile", "rb") as infile:
    str = base64.b85encode(imageFile.read())

with open("bytesfile", "rb") as infile:
    str2 = json.dumps(list(infile.read()))

Но это не очень эффективно,. Получится 2 МБ картинку в 9 МБ.

Комментарии (0)

Для конкретных случае "запустить команду оболочки и сделать свой вывод как текст, а не байт-то", на Python 3.7, вы должны использовать подпроцесса.запустить и передать в тексте=правда(а такжеcapture_output=правда`, чтобы захватить выходные)

command_result = subprocess.run(["ls", "-l"], capture_output=True, text=True)
command_result.stdout  # is a `str` containing your program's stdout

текст называли universal_newlines, и был изменен (ну, псевдоним) в Python 3.7. Если вы хотите поддержка Python до версии 3.7, пройти в universal_newlines=правдавместотекст=правда`

Комментарии (0)