tags:

views:

1045

answers:

5

I have a non-negative int and I would like to efficiently convert it to a big-endian string containing the same data. For example, the int 1245427 (which is 0x1300F3) should result in a string of length 3 containing three characters whose byte values are 0x13, 0x00, and 0xf3.

My ints are on the scale of 35 (base-10) digits.

How do I do this? Thanks.

+2  A: 

You can use the struct module:

import struct
print struct.pack('>I', your_int)

'>I' is a format string. > means big endian and I means unsigned int. Check the documentation for more format chars.

Ayman Hourieh
struct.pack returns a fixed length string and doesn't seem to have facilities for handling large ints. I suppose I could break my int into powers of 2^32, run it through struct.pack(), and reassemble the result, but that seems like a lot of work...do you know of a simpler way?
fish
I couldn't find a library to handle arbitrary long ints. I think you will have to implement it yourself. Other answers contain implementations.
Ayman Hourieh
Ayman, note that Python has built-in support for arbitrarily long ints, so you don't need a library. In Python 3, there will only be the `int` type, but even now in Python 2.4+, `int`s are automatically converted to Python `long`s when they overflow 32 bits (signed).
benhoyt
benhoyt, thanks for the comment. I'm aware of this. I was talking about handling the conversion of arbitrary long ints to big endian. Not handling them in general.
Ayman Hourieh
+1  A: 

Probably the best way is via the built-in struct module:

>>> import struct
>>> x = 1245427
>>> struct.pack('>BH', x >> 16, x & 0xFFFF)
'\x13\x00\xf3'
>>> struct.pack('>L', x)[1:]  # could do it this way too
'\x13\x00\xf3'

Alternatively -- and I wouldn't usually recommend this, because it's mistake-prone -- you can do it "manually" by shifting and the chr() function:

>>> x = 1245427
>>> chr((x >> 16) & 0xFF) + chr((x >> 8) & 0xFF) + chr(x & 0xFF)
'\x13\x00\xf3'

Out of curiosity, why do you only want three bytes? Usually you'd pack such an integer into a full 32 bits (a C unsigned long), and use struct.pack('>L', 1245427) but skip the [1:] step?

benhoyt
+2  A: 
def tost(i):
  result = []
  while i:
    result.append(chr(i&0xFF))
    i >>= 8
  result.reverse()
  return ''.join(result)
Alex Martelli
+3  A: 
def Dump(n): 
  s = '%x' % n
  if len(s) & 1:
    s = '0' + s
  return s.decode('hex')
print repr(Dump(1245427))  #: '\x13\x00\xf3'
pts
+1  A: 

Using the bitstring module:

>>> bitstring.BitString(uint=1245427, length=24).bytes
'\x13\x00\xf3'

Note though that for this method you need to specify the length in bits of the bitstring you are creating.

Internally this is pretty much the same as Alex's answer, but the module has a lot of extra functionality available if you want to do more with your data.

Scott Griffiths