Как передать строку в байты без кодирования

63
4

У меня есть куча двоичных данных, которые поступают на python через char * из некоторого C-интерфейса (не под моим контролем), поэтому у меня есть строка произвольных двоичных данных (обычно это байтовый массив). Я хотел бы преобразовать его в массив байтов, чтобы упростить его использование с другими функциями python, но я не могу понять, как это сделать.

Примеры, которые не работают:

data = rawdatastr.encode() это предполагает "utf-8" и управляет данными == BAD

data = rawdatastr.encode('ascii','ignore') разделяет символы над 127 == BAD

data = rawdatastr.encode('latin1') не уверен - это самое близкое до сих пор, но у меня нет доказательств того, что он работает для всех байтов.

data = array.array('B', [x for x in map(ord,data)]).tobytes() Это работает, но кажется, что много работы сделать что-то простое. Есть что-то более простое?

Я думаю, что мне нужно написать свою собственную идентификационную кодировку, которая просто передает байты (я думаю, что latin1 делает это на основе некоторого чтения, но до сих пор нет доказательств).

спросил(а) 2021-01-25T11:14:02+03:00 4 месяца, 3 недели назад
1
Решение
99

Хотя я подозреваю, что что-то еще расшифровывает ваши данные для вас (char* в C обычно лучше всего представляется в виде bytes, особенно если это двоичные данные):

Кодек latin1 может перемещаться в каждом байте. Вы можете проверить это с помощью следующей короткой программы:

>>> s = ''.join(chr(i) for i in range(0xff))
>>> s
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0¡¢£¤¥¦§¨©ª«¬\xad®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ'
>>> s2 = s.encode('latin1').decode('latin1')
>>> s2 == s
True
>>> sb = bytes(range(0xff))
>>> sb
b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe'
>>> sb == s.encode('latin1')
True

ответил(а) 2021-01-25T11:14:02+03:00 4 месяца, 3 недели назад
77

Только сейчас я столкнулся с той же проблемой. Вот что я придумал:

import struct

def rawbytes(s):
"""Convert a string to raw bytes without encoding"""
outlist = []
for cp in s:
num = ord(cp)
if num < 255:
outlist.append(struct.pack('b', num))
elif num < 65535:
outlist.append(struct.pack('>H', num))
else:
b = (num & 0xFF0000) >> 16
H = num & 0xFFFF
outlist.append(struct.pack('>bH', b, H))
return b''.join(outlist)


Некоторые примеры:

In [34]: rawbytes('this is a test')
Out[34]: b'this is a test'

In [35]: rawbytes('\udc80\udcdf\udcff\udcff\udcff\x7f')
Out[35]: b'\xdc\x80\xdc\xdf\xdc\xff\xdc\xff\xdc\xff\x7f'

ответил(а) 2021-01-25T11:14:02+03:00 4 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема