Seite 1 von 1

bytestring bzw. bytearray to int (signed / unsigned)

Verfasst: Freitag 24. Januar 2020, 20:57
von sisamiwe
Hallo,
ich habe folgende Aufgabe.

Ich bekomme einen Bytestring bzw. eine bytearray wie bspw a = bytearray(b'G\xc3\x00\x00'
Darin sind integer Werte verpackt. Die Codierung ist: (Wert des ersten Byte in Dec* x 256^0) + (Wert des zweiten Byte in Dec x 256^1) + (Wert des dritten Byte in Dec x 256^3) + usw.

Die Ergebnisse können signed oder unsigned sein. Ich weiß, welcher Werte signed sind und welche unsigned.

Bislang habe ich das so gelöst.

Code: Alles auswählen

    def decode_rawvalue(self, rawdatabytes, commandsignage):
        byteindex = 0
        rawvalue = 0
        while (len(rawdatabytes) > 0):
            # Erstes Byte zwischenspeichern
            leftbyte = rawdatabytes[:1]
            # Wert des Bytes ermitteln
            value = int(ord(leftbyte))
            # Gewichten / Multiplizieren
            if (byteindex > 0):
                value = int(value * pow(256, byteindex))
            # Aufaddieren der einzelnen Bytes
            rawvalue = rawvalue + value
            # Byteindex hochzählen, damit das Byte mit entsprechend mit 1, 256, 65536, 16777216, usw. multipliziert werden kann
            byteindex = byteindex + 1
            # Bytestring um das erste Byte verkürzen
            rawdatabytes = rawdatabytes[1:]
        # Signed/Unsigned berücksichtigen
        if (commandsignage == 'signed'):
            if ((byteindex == 1) and (rawvalue > 127)):
                rawvalue = (256 - rawvalue) * (-1)
            elif ((byteindex == 2) and (rawvalue > 32767)):
                rawvalue = (65536 - rawvalue) * (-1)
            #elif ((byteindex == 4) and (rawvalue > 2147483647‬)):
            #    rawvalue = (4294967296‬ - rawvalue) * (-1)
        return rawvalue
Das geht bestimmt auch besser. Habt ihr Ideen?

Re: bytestring bzw. bytearray to int (signed / unsigned)

Verfasst: Freitag 24. Januar 2020, 21:36
von snafu
Die Schleife ist eigentlich ein Einzeiler:

Code: Alles auswählen

sum(value * 256**i for i, value in enumerate(rawbytes))
Oder gleich die eingebaute Methode benutzen:

Code: Alles auswählen

int.from_bytes(rawbytes, 'little')

Re: bytestring bzw. bytearray to int (signed / unsigned)

Verfasst: Freitag 24. Januar 2020, 21:39
von sisamiwe
@snafu
Danke.

Und wie kann ich das Ergebnis dann ggf noch in signed wandeln?

Re: bytestring bzw. bytearray to int (signed / unsigned)

Verfasst: Freitag 24. Januar 2020, 21:57
von snafu
Ich kenne ja den genauen Hintergrund nicht, aber womöglich kommst du auch mit dem struct-Modul zum Ziel:

Code: Alles auswählen

import struct

def decode(data, signed=True):
    format = '<' + ('i' if signed else 'I')
    result = struct.unpack(format, data)
    return result[0]
Das "<" bestimmt hier die Byteorder (Little Endian). Die ist oft vom System eh schon als "little" eingestellt, kann aber auch "big" sein und dann kämen bei der Ausführung auf einem solchen Rechner ganz andere Ergebnisse heraus.

Re: bytestring bzw. bytearray to int (signed / unsigned)

Verfasst: Samstag 25. Januar 2020, 08:51
von sisamiwe
@snafu

Zum Hintergrund: Ich lese eine serielle Schnittstelle ein. Aus den Telegrammen extrahiere ich mir die Payload, oder besser gesagt die Bytes, die die Werte enthalten. Wie viele Wert-Bytes im Telegram sind, ist mir bekannt. Ebenfalls ist bekannt, ob ich diesen Wert als signed oder unsigned behandeln muss. An der Stelle, wo die Funktion ausgeführt wird, habe ich die Bytes, die die Werte enthalten, schon separiert, sprich, dass was ich hier als bytearray angeben, sind die reinen Wertbytes.

Hier mal eine kleine Auswahl an möglichen Wertebytes:

Code: Alles auswählen

rawbytes = bytearray(b'G\xc3\x00\x00')
rawbytes = bytearray(b'N\xc3\x00\x00')
rawbytes = bytearray(b'!(\xff\xff\xff\xff\xff\xff')
rawbytes = bytearray(b'\x19p\x01\x01\x04\x00\x00\x00')
rawbytes = bytearray(b'\xbc\x01')
Die Aufgabe ist, jeweils die rawbytes in signed oder unsigned integer zu wandeln.

Wie kann man das effizient machen?
DANKE

Re: bytestring bzw. bytearray to int (signed / unsigned)

Verfasst: Samstag 25. Januar 2020, 09:10
von __blackjack__
@sisamiwe: Klingt nach einer Aufgabe für das `struct`-Modul und das Du die Werte eventuell zu früh separiert hast, denn für `struct` würde es sich anbieten ganze Telegramme zu decodieren.

Re: bytestring bzw. bytearray to int (signed / unsigned)

Verfasst: Samstag 25. Januar 2020, 10:49
von Sirius3
Auch wenn die Lösung mit struct.unpack ein Einzeiler ist, hier noch ein paar Anmerkungen zu deinem Code:
Die Bedingungen by while und if brauchen alle keine Klammern. Weg damit.
Die Kommentare sind allesamt überflüssig weil sie nur beschreiben was in der darauffolgenden Zeile sowieso steht.
Wenn Du gleich auf rawdatabytes[0] zugreifen würdest, wäre int und ord überflüssig.
Das `if (byteindex > 0):` ist unnötig, weil 256 hoch 0 eins ergibt.
Statt byteindex händisch hoch zu zählen, wäre hier statt der while-Schleife eine for-Schleife günstiger.

Re: bytestring bzw. bytearray to int (signed / unsigned)

Verfasst: Samstag 25. Januar 2020, 12:35
von snafu
int.from_bytes() hat noch eine weitere Option, die ich nicht mehr im Kopf hatte. Somit benötigt man das struct-Modul gar nicht mehr:

Code: Alles auswählen

int.from_bytes(rawbytes, byteorder='little', signed=True)
...wobei du den signed-Parameter natürlich entsprechend anpassen kannst.