How do I interpret a string containing a sequence of bytes as a sequence of bytes?

Viewed 46

I have an instrument that returns a string with the format:

StrInstrument = '\xE0\x31\xFF\xCF\xFF\xCA\xFF\xC4'

I have to perform operations with the data in the string. In order to do so, in the code I should convert it from little endian with the function struct.unpack(). I tried to interpret the string as bytes using the bytes() function but it does not work, probably because it tries to convert my string to bytes instead of changing the interpretation:

print(bytes(StrInstrument,'utf-8'))
iValues = struct.unpack('HHHH',bytes(StrInstrument,'utf-8'))
print(iValues)

b'\xc3\xa01\xc3\xbf\xc3\x8f\xc3\xbf\xc3\x8a\xc3\xbf\xc3\x84' error: unpack requires a buffer of 8 bytes

After changing the buffer to 'HHHHHHHH':

b'\xc3\xa01\xc3\xbf\xc3\x8f\xc3\xbf\xc3\x8a\xc3\xbf\xc3\x84' error: unpack requires a buffer of 16 bytes

Instead, the code works fine if I simply write this:

iValues = struct.unpack('HHHH',b'\xE0\x31\xFF\xCF\xFF\xCA\xFF\xC4')
print(iValues)

(12768, 53247, 51967, 50431)

Is there a way to do this without writing the string in the function?

1 Answers

Your string is already encoded, so you need it converted "raw":

struct.unpack('HHHH',StrInstrument.encode('raw_unicode_escape'))

If what you want is not what you have in a question, but actual backslashes in your string, i.e:

StrInstrument = r'\xE0\x31\xFF\xCF\xFF\xCA\xFF\xC4'  # r-string instead of writing \\ everywhere

then to convert it to what you have in the question:

b''.join([int(num, 16).to_bytes(1, 'little') for num in StrInstrument.split('\\x') if num])  # little or big doesn't actually matter for a single byte

and then encoding is not needed as you have the bytes object already:

struct.unpack('H'*4, b''.join([int(num, 16).to_bytes(1, 'little') for num in StrInstrument.split('\\x') if num]))

although, how would you get such a string? Likely this could have been done better, depending on how this string was constructed.

Related