Search code examples
pythontcphex

Python format hex number


I need to send a string via tcp. One of the first sections of the string is the length of the command variable

Example:
command = STATUS?UPDATE

I need to send the following string below

sendCommand = '\x00\x00\x00'+STRINGLENGTH+'\x02'+command+'\x0D\x0A'

My string length is 11 so I need STRINGLENGTH to be the hex equivalent of 11, which is 0xB, except that I need it to output as \x0B

Padding it with the leading 0 is easy, but I cannot get it to output as \x instead of 0x, and if I do a string replace it is treated as text and not as hex, so it doesn't work.

My final hex string should be:

\x00\x00\x00\x0B\x02\x53\x54\x41\x54\x55\x53\x3f\x55\x53\x45\x52\x0D\x0A

I am instead getting:

\x00\x00\x000x0B\x02\x53\x54\x41\x54\x55\x53\x3f\x55\x53\x45\x52\x0D\x0A

Any ideas on how to format it correctly?


Solution

  • So, this is a bit of a round-about fashion, but use a bytes object:

    >>> STRINGLENGTH = bytes([11]).decode()
    >>> endCommand = '\x00\x00\x00'+STRINGLENGTH+'\x02'
    >>> endCommand
    '\x00\x00\x00\x0b\x02'
    

    Almost certainly, you are going to want to change your str object back to a bytes object, but the above should get you going.

    I suspect what you were doing was using the hex function:

    >>> STRINGLENGTH = hex(11)
    >>> endCommand = '\x00\x00\x00'+STRINGLENGTH+'\x02'
    >>> endCommand
    '\x00\x00\x000xb\x02'
    

    The fundamental thing you need to understand is that you aren't working with "hex", you are working with bytes. Hex is just how bytes are traditionally represented. The hex helper function returns a hexadecimal representation, as a string of an integer. But that isn't what you want. You want the byte corresponding to the value 11.

    Note, for the ascii-range, chr(i) might works as well, so

    >>> STRINGLENGTH = chr(11)
    >>> endCommand = '\x00\x00\x00'+STRINGLENGTH+'\x02'
    >>> endCommand
    '\x00\x00\x00\x0b\x02'
    

    But be careful, say you wanted the number 129, you have to care about the encoding...

    >>> chr(129)
    '\x81'
    

    But in bytes, in UTF-8, that's actually represented by two different bytes

    >>> chr(129).encode()
    b'\xc2\x81'
    >>> list(chr(129).encode())
    [194, 129]
    

    Which of course, depends on the encoding:

    >>> chr(129).encode('latin')
    b'\x81'
    >>> list(chr(129).encode('latin'))
    [129]
    >>>
    

    For that reason, I think it is safer to stick with the slightly wordier:

    >>> bytes([129])
    b'\x81'