Конвертировать байты в строку?
Я использую этот код, чтобы получить стандартный вывод из внешней программы:
>>> 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.
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. Смотрите недостающие точки в Макет Кодовой Страницы - это где питон задыхается с позорным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 может быть любая последовательность байтов, кроме slashb'/'и ноль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