Конвертировать байты в строку?



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



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


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



>>> command_stdout
b'total 0n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file1n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file2n'


тем не менее, я хотел бы работать с выводом как обычная строка 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 0n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file1n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file2n'


кто-нибудь знает как чтобы преобразовать значение байтов обратно в строку? Я имею в виду, используя "батареи" вместо того, чтобы делать это вручную. И я хотел бы, чтобы все было в порядке с Python 3.

512   16  

16 ответов:

вам нужно декодировать объект 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'

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

bytes = [112, 52, 52]
"".join(map(chr, bytes))
>> p44

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

b'hello'.decode(encoding)

или

str(b'hello', encoding)

если вы не знаете кодировку, то для чтения двоичного ввода в строку в Python 3 и Python 2 совместимый способ, используйте древний MS-DOS 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 "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 2: invalid
start byte

то же самое относится к latin-1, который был популярен (по умолчанию?) для Python 2. Смотрите недостающие точки в Макет Кодовой Страницы - это где питон задыхается с позорным ordinal not in range.

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

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

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

посмотреть https://docs.python.org/3/howto/unicode.html#python-s-unicode-support Для сведения.

обновление 20170119: я решил реализовать slash escaping decode, который работает как для Python 2, так и для Python 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'))

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

b'hello'.decode()

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

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

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

b'hello'.decode(encoding)

здесь encoding - это кодировка, которую вы хотите.

Примечание: поддержка ключевых аргументов была добавлена в Python 2.7.

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

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

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

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

установить universal_newlines в True, т. е.

command_stdout = Popen(['ls', '-l'], stdout=PIPE, universal_newlines=True).communicate()[0]

пока @Аарон мяэнпяа: дизайн для всех это!--5--> работает, а недавно попросил

есть ли более простой способ? - фханд.читать.)(decode ("ASCII")' [...] Это так долго!

можно использовать

command_stdout.decode()

decode() есть стандартный аргумент

codecs.decode(obj, encoding='utf-8', errors='strict')

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

unicode_text = bytestring.decode(character_encoding)

пример:

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

ls команда может выдавать выходные данные, которые не могут быть интерпретированы как текст. Имя файла в Unix может быть любая последовательность байтов, кроме slash b'/' и ноль b'':

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

попытка декодировать такой байтовый суп с помощью кодировки utf-8 вызываетUnicodeDecodeError.

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

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

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

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


ls вывод может быть преобразован в строку Python с помощью os.fsdecode() функция, которая преуспевает даже для undecodable имена файлов (его использует sys.getfilesystemencoding() и surrogateescape обработчик ошибок на Unix):

import os
import subprocess

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

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

если вы передадите затем subprocess использует locale.getpreferredencoding(False) для декодирования байтов, например, он может быть cp1252 на Windows.

для декодирования потока байтов на лету, io.TextIOWrapper() можно использовать:пример.

различные команды могут использовать различные кодировки для их вывод, например,dir внутренняя команда (cmd) может использовать cp437. Чтобы декодировать его вывод, вы можете передать кодировку явно (Python 3.6+):

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

имена файлов могут отличаться от os.listdir() (который использует Windows Unicode API) например,'\xb6' можно заменить на '\x14'-в Python cp437 кодек карты b'\x14' для управления символом U + 0014 вместо U + 00B6 (¶). Для поддержки имен файлов с произвольными символами Юникода см. раздел Декодируйте вывод poweshell, возможно, содержащий символы unicode, отличные от ascii, в строку python

так как этот вопрос на самом деле спрашивает о subprocess выход, у вас есть более прямой подход, поскольку 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(), то вы должны указать кодировку явно в decode звоните:

>>> b'caf\xe9'.decode('cp1250')
'café'

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

AttributeError: 'str' object has no attribute 'decode'

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

>>> my_byte_str
b'Hello World'

>>> str(my_byte_str, 'utf-8')
'Hello World'

Я сделал функцию для очистки списка

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

при работе с данными из систем Windows (с \r\n окончание строки), Мой ответ

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

почему? Попробуйте сделать это с помощью многострочного ввода.txt:

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

все ваши окончания строки будут удвоены (до \r\r\n), что приводит к дополнительной пустой строки. Функции чтения текста Python обычно нормализуют окончания строк, так что строки используют только \n. Если вы получаете двоичные данные из системы Windows, Python не имеет возможности сделать это. Таким образом,

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

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

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

def byte_to_str(bytes_or_str):
    if isinstance(bytes_or_str, bytes): #check if its 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
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))

от http://docs.python.org/3/library/sys.html,

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

Comments

    Ничего не найдено.