4

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')
2
  • 1
    You don't want to convert your number to a hex string at all; you want to convert it to a binary representation, or base256. Commented Mar 31, 2009 at 0:28
  • 1
    ack, "hex string" is really not the correct term here Commented Mar 31, 2009 at 6:28

7 Answers 7

6

You can use string formatting:

>>> number = 123456789
>>> hex = "%X" % number
>>> hex
'75BCD15'
Sign up to request clarification or add additional context in comments.

6 Comments

Ah nice, now how do I get it so it will output '\x75\xbc\d1\x05'?
You can use lowercase x to make it display in lowercase, I am not sure about the other part...
Well hex(number)[2:-1].decode('hex') does that except it messes up sometimes.
I'm pretty sure you mean [2:], not [2:-1] — the latter cuts off the last digit.
Ben: Oh yeah, that's another problem, sometimes hex() sticks an 'L' at the end.
|
5

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'

1 Comment

I need something that can take a number bigger than an Int or long.
1

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.

6 Comments

Wrong way. I'm trying to go from int to hex, not hex to int.
Sorry, I both misread and misremembered stuff. The answer is changed now.
(To me) it makes more sense to add a leading 0. See my answer. The code can easily be adjusted if a trailing space is preferred.
Yours doesn't answer his question either, though. It returns '\\x0F' instead of '\x0F'. The real answer is a one-liner-- (('0' + foo) if len(foo) % 2 else foo).decode('hex')
@Devin I (incorrectly?) assumed that he wants to have a literal backslash instead of the actual hex value in the string.
|
1
'{0:b}'.format( number )

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

Comments

0

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'

1 Comment

Is there a way to automatically detect the length based on the size of the number?
0

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.

2 Comments

Yes I know but I need it to convert to '\x2a' not '2a'
Thank you for the input. It is almost the same as the snippet I just made, but I didn't want it to be escaped, so I guess it would need a char() instead of ''.join('\\x")
0

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()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.