Unknown
Unknown

Reputation: 46821

Convert number to binary string

Is this the best way to convert a Python number to a hex string?

number = 123456789
hex(number)[2:-1].decode('hex')

Sometimes it doesn't work and complains about Odd-length string when you do 1234567890.

Clarification:

I am going from int to hex.

Also, I need it to be escaped.

IE: 1234567890 -> '\x49\x96\x02\xd2' not '499602D2'

Also, it needs to be able to take any Python integer. IE. something larger than an Int.

Edit:

Here is the best solution so far I have cobbled together from Paolo and Devin's post.

def hexify(num):
    num = "%x" % num

    if len(num) % 2:
        num = '0'+num

    return num.decode('hex')

Upvotes: 4

Views: 6806

Answers (7)

Saw-mon and Natalie
Saw-mon and Natalie

Reputation: 457

'{0:b}'.format( number )

refer to http://docs.python.org/library/string.html

Upvotes: 1

Vishal
Vishal

Reputation: 589

one of the surest way, for arbitary numbers, is to use the 'array' module like this:

from array import array
binArr = array('B')

while(data):
    d = data & 0xFF
    binArr.append(d)
    data >>= 8

hexStr = binArr.tostring()

Upvotes: 0

Stephan202
Stephan202

Reputation: 61589

As Paolo mentioned, string formatting is the way to go. Note that you can choose between lower and upper case letters:

>>> hex = lambda n: '%X' % n
>>> hex(42)
'2A'
>>> hex = lambda n: '%x' % n
>>> hex(42)
'2a'
>>> def escaped(n):
...     s = hex(n)
...     if len(s) & 1:
...          s = '0' + s
...     return ''.join(chr(int(s[i:i + 2], 16)) for i in range(0, len(s), 2))
...
>>> escaped(123)
'{'
>>> escaped(1234)
'\x04\xd2'
>>> escaped(12348767655764764654764445473245874398787989879879873)
'!\x01^\xa4\xdf\xdd(l\x9c\x00\\\xfa*\xf3\xb4\xc4\x94\x98\xa9\x03x\xc1'

Note that escaped adds a leading zero in case of an odd number of hex digits. This solution works for strings of any length.

Upvotes: 0

John Fouhy
John Fouhy

Reputation: 42203

I'm not sure exactly what you want, but have you looked at the struct module?

Given

>>> hex(123456789)
'0x75bcd15'

You can do:

>>> struct.pack('i', 123456789)
'\x15\xcd[\x07'

Note that '\x5b' == '['.

Also, you can reverse the endianness:

>>> struct.pack('>i', 123456789)
'\x07[\xcd\x15'

Edit: I'm not sure what you mean by "bigger than a long", since AFAIK longs in python are unbounded (except by memory). However, you can deal with bigger integers by just dividing and concatenating. e.g. given:

>>> n = 123456789012345678901234567890

the target is:

>>> hex(n)
'0x18ee90ff6c373e0ee4e3f0ad2L'

So:

>>> s = ''
>>> while n >= 2**32:
...  n, r = divmod(n, 2**32)
...  s = struct.pack('>l', r) + s
... 
>>> s = struct.pack('>l', n) + s

See that s matches the result of hex(n) above:

>>> s
'\x00\x00\x00\x01\x8e\xe9\x0f\xf6\xc3s\xe0\xeeN?\n\xd2'

Upvotes: 5

Ben Blank
Ben Blank

Reputation: 56624

If you know how long your output strings should be, string formatting will work. For example, to get four-character strings, you need a formatted length of eight:

>>> "{0:08x}".format(123456789).decode("hex")
'\x07[\xcd\x15'
>>> "{0:08x}".format(1234567890).decode("hex")
'I\x96\x02\xd2'

This will prepend zeroes if your number doesn't "fill up" the string. For example, with six-character strings:

>>> "{0:012x}".format(123456789).decode("hex")
'\x00\x00\x07[\xcd\x15'
>>> "{0:012x}".format(1234567890).decode("hex")
'\x00\x00I\x96\x02\xd2'

Edit:

To "detect" the length of target strings, you can use the math.log function:

>>> def int2str(n):
        l = int(math.ceil(math.log(n, 256) / 2) * 4)
        return ("{0:0{1}x}").format(n, l).decode("hex")

>>> int2str(123456789)
'\x07[\xcd\x15'
>>> int2str(1234567890)
'I\x96\x02\xd2'

Upvotes: 0

Devin Jeanpierre
Devin Jeanpierre

Reputation: 95606

Sometimes it doesn't work and complains about Odd-length string when you do 1234567890.

Because it doesn't make sense. How do you fit 'AAB' in a space that takes either 2 or 4 digits? Each byte is two hex characters. When you have an odd number of hex characters, the desired result is ambiguous. Do you want it to be the equivalent of 0AAB or AAB0? If you know which one you want it to be equivalent to, just add that character to the right place before decoding.

i.e. (('0' + foo) if len(foo) % 2 else foo).decode('hex') where foo is a string of the form returned by %x.

Upvotes: 1

Paolo Bergantino
Paolo Bergantino

Reputation: 488694

You can use string formatting:

>>> number = 123456789
>>> hex = "%X" % number
>>> hex
'75BCD15'

Upvotes: 6

Related Questions