2

What is the most pythonic way to convert an integer into a hex-escaped string?

0 -> '\x00'

15 -> '\x0f'

0xdeadbeef -> '\xde\xad\xbe\xef'

Community
  • 1
  • 1
0x00
  • 217
  • 1
  • 7
  • 2
    @Lix: This is definitely NOT a duplicate of that question, which asks specifically about values <256, which has a trivial solution. – Aleksi Torhamo May 17 '15 at 10:31

3 Answers3

4

There's no way to do what you want directly, but it's not that hard to do yourself.

For example, you can convert the whole int to hex, then insert a \x character before every pair of characters:

n = 0xdeadbeef
x = format(n, 'x')
s = re.sub('(..)', r'\\x\1', x)
# or s = ''.join(r'\x{}{}'.format(*b) for b in pairwise(x))
# or s = ''.join(r'\x' + x[i:i+2] for i in range(0, len(x), 2))

Or you could pull off a byte at a time and format them yourself:

x = []
while n:
    x.append(n % 256)
    n //= 256
s = ''.join(r'\x{:02x}'.format(b) for b in reversed(x))

Which of those is most Pythonic? I think they're all simple enough that if you wrapped them up in a function with an appropriate name, nobody would complain, but all complicated enough that if you just inlined them into your code, it wouldn't be very pythonic. (I'd personally use the pairwise version, just because I always think of itertools first, but that's just me.)

abarnert
  • 354,177
  • 51
  • 601
  • 671
1

It's a bit ambiguous whether you want the 1-byte string '\x0f' or the 6-byte string "'\\x0f'" (ie. a string which looks like '\x0f' when printed). In case you meant the former, here's one way to do that:

s = '%x' % 0xdeadbeef
binascii.unhexlify('0' + s if len(s) % 2 else s)
Aleksi Torhamo
  • 6,452
  • 2
  • 34
  • 44
1

Not sure how 'pythonic' that is, but here's a solution using a recursive function:

def uint_tuple_to_bytes(t):
        if t[0] < 0x100:
                return t
        else:
                return uint_tuple_to_bytes(divmod(t[0], 0x100) + t[1:])

def uint_to_bytes(i):
        return uint_tuple_to_bytes((i,))

def uint_to_binary_string(i):
        return ''.join(chr(byte) for byte in uint_to_bytes(i))

(Inspired by the second part ("pull off a byte at a time") of abarnert's answer and by msvalkon's answer to 'How to split 16-bit unsigned integer into array of bytes in python?'.)

Community
  • 1
  • 1
das-g
  • 9,718
  • 4
  • 38
  • 80