Преобразовать байты в строку?
Я использую этот код для получения стандартного вывода из внешней программы:
>>> 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'
кто-нибудь знает как чтобы преобразовать значение bytes обратно в string? Я имею в виду, используя "батареи" вместо того, чтобы делать это вручную. И я бы хотел, чтобы с Python 3 все было в порядке.
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'
вам нужно декодировать строку байта и превратить ее в символьную строку (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. Смотрите недостающие точки в Макет Кодовой Страницы - это где Python задыхается с печально известным 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--> работает, а недавно попросил
есть ли более простой способ? 'fhand.читать.)(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
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
to 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').