So, I've been banging my head against the wall for too long on what seems like it should be an easy data conversion. I am writing in python and passing to another module a hex value that is converted with a wrapper to c type uint_64t. the problem is I am getting this hex value via the python library argparse. When it takes in this value, for example lets use the value 0x3f, it saves it as a string. If I try to cast this as an int it throws the error:
"ValueError: invalid literal for int() with base 10: '0x3f'"
If I create a variable hex = 0x3f however, when I print it out, it gives me the appropriate integer value. (which is great since I'm creating a uint) I am just confused how to make the conversion from string to int if a cast doesn't work. I have seen plenty of examples on turning this string into a hex value by letter (in other words take each individual character of the ascii string '0x3f' and give it a hex value) but I haven't been able to find an example of the situation I am looking for. Apologies if I'm bringing up something that has been answered time and again.
Try specifying that the int is in base 16:
>>> int("0x3f", 16)
63
You could also use ast.literal_eval, which should be able to read any string that could be used as an integer literal. You don't even have to specify a base for this one, as long as the 0x prefix is present.
>>> import ast
>>> #hexadecimal
>>> ast.literal_eval("0x3f")
63
>>> #binary
>>> ast.literal_eval("0b01010")
10
>>> #octal
>>> ast.literal_eval("0712")
458
>>> #decimal
>>> ast.literal_eval("42")
42
int takes an optional second argument, which is the numerical base to use for conversion. The default is 10 (decimal conversion) but you can change it to 16 (for hex) or 0 (for automatic conversion based on prefix):
>>> int('0b1010', 0)
10
>>> int('0x3f', 0)
63
>>> int('0o777', 0)
511
>>> int('1234', 0)
1234
Related
Let's assume that I get number as string or hex or int and I want to convert to integer. I'm looking for a more generic form.
for example,
if I write:
int('0x10',16) then int('0x10') will throw exception.
if I write:
int('10') then int('10',16) will throw exception.
Do I need to check type with instanceof ?
If the string represents a valid hex, it is prefixed by 0x. So, you could just check value.startswith('0x')
You need to specify the base (docs), when using int() on a hex value:
>>> _hex = hex(int("32"))
>>> _hex
'0x20'
>>> int(_hex, 0) # 0 means: Python automatically detects hex or decimal
32
I want to get the value of 99997 in big endian which is (2642804992) and then return the answer as a long value
here is my code in python:
v = 99997
ttm = pack('>i', v) # change the integer to big endian form
print ("%x"), {ttm}
r = long(ttm, 16) # convert to long (ERROR)
return r
Output: %x set(['\x00\x01\x86\x9d'])
Error: invalid literal for long() with base 16: '\x00\x01\x86\x9d'
As the string is already in hex form why isn't it converting to a long? How would I remove this error and what is the solution to this problem.
pack will return a string representation of the data you provide.
The string representation is different than a base 16 of a long number. Notice the \x before each number.
Edit:
try this
ttm = pack('>I',v)
final, = unpack('<I',ttm)
print ttm
Notice the use of I, this so the number is treated as an unsigned value
You have to use struct.unpack as a reverse operation to struct.pack.
r, = unpack('<i', ttm)
this will r set to -1652162304.
You just converted the integer value to big endian binary bytes.
This is useful mostly to embed in messages addressed to big-endian machines (PowerPC, M68K,...)
Converting to long like this means parsing the ttm string which should be 0x1869D as ASCII.
(and the print statement does not work either BTW)
If I just follow your question title: "Convert hexadecimal string to long":
just use long("0x1869D",16). No need to serialize it.
(BTW long only works in python 2. In python 3, you would have to use int since all numbers are represented in the long form)
Well, I'm answering to explain why it's bound to fail, but I'll edit my answer when I really know what you want to do.
This is a nice question.
Here is what you are looking for.
s = str(ttm)
for ch in r"\bx'":
s = s.replace(ch, '')
print(int(s, 16))
The problem is that ttm is similar to a string in some aspects. This is what is looks like: b'\x00\x01\x86\x9d'. Supplying it to int (or long) keeps all the non-hex characters. I removed them and then it worked.
After removing the non-hex-digit chars, you are left with 0001869d which is indeed 99997
Comment I tried it on Python 3. But on Python 2 it will be almost the same, you won't have the b attached to the string, but otherwise it's the same thing.
In Python 3.3 I need to convert an integer into the middle of three bytes to send it over a serial connection.
That is, I need to have a value of: b'\x4c\x00\x46', except that the \x00 byte will need to take the single-byte value of an integer variable that may vary from 0 to 255. I thought chr(value) would work, but that gives a string rather than a byte.
For example, if value is 255, I want to get b'\x4c\xff\x46'.
Using bytearray:
>>> b'\x4c\x00\x46'
b'L\x00F'
>>> a = bytearray(b'\x4c\x00\x46')
>>> a[1] = 255
>>> a
bytearray(b'L\xffF')
>>> bytes(a)
b'L\xffF'
You can also use list in place of bytearray. But using list does not work in Python 2.x.
I have a script that calls a function that takes a hexadecimal number for an argument. The argument needs to the 0x prefix. The data source is a database table and is stored as a string, so it is returned '0x77'. I am looking for a way to take the string from the database and use it as an argument in hex form with the 0x prefix.
This works:
addr = 0x77
value = class.function(addr)
The database entry has to be a string, as most of the other records do not have hexadecimal values in this column, but the values could be changed to make it easier, so instead of '0x77', it could be '119'.
Your class.function expects an integer which can be represented either by a decimal or a hexadecimal literal, so that these two calls are completely equivalent:
class.function(0x77)
class.function(119) # 0x77 == 119
Even print(0x77) will show 119 (because decimal is the default representation).
So, we should rather be talking about converting a string representation to integer. The string can be a hexadecimal representation, like '0x77', then parse it with the base parameter:
>>> int('0x77', 16)
119
or a decimal one, then parse it as int('119').
Still, storing integer whenever you deal with integers is better.
EDIT: as #gnibbler suggested, you can parse as int(x, 0), which handles both formats.
>>> hex(119)
'0x77'
#or:
>>> hex(int("119"))
'0x77'
This should work for you.
You can also get the hex representation of characters:
>>> hex(ord("a"))
'0x61'
I think you're saying that you read a string from the database and you want to convert it to an integer, if the string has the 0x prefix you can convert it like so:
>>> print int("0x77", 16)
119
If it doesnt:
>>> print int("119")
119
I want to convert an integer value to a string of hex values, in little endian. For example, 5707435436569584000 would become '\x4a\xe2\x34\x4f\x4a\xe2\x34\x4f'.
All my googlefu is finding for me is hex(..) which gives me '0x4f34e24a4f34e180' which is not what I want.
I could probably manually split up that string and build the one I want but I'm hoping somone can point me to a better option.
You need to use the struct module:
>>> import struct
>>> struct.pack('<Q', 5707435436569584000)
'\x80\xe14OJ\xe24O'
>>> struct.pack('<Q', 5707435436569584202)
'J\xe24OJ\xe24O'
Here < indicates little-endian, and Q that we want to pack a unsigned long long (8 bytes).
Note that Python will use ASCII characters for any byte that falls within the printable ASCII range to represent the resulting bytestring, hence the 14OJ, 24O and J parts of the above result:
>>> struct.pack('<Q', 5707435436569584202).encode('hex')
'4ae2344f4ae2344f'
>>> '\x4a\xe2\x34\x4f\x4a\xe2\x34\x4f'
'J\xe24OJ\xe24O'
I know it is an old thread, but it is still useful. Here my two cents using python3:
hex_string = hex(5707435436569584202) # '0x4f34e24a4f34e180' as you said
bytearray.fromhex(hex_string[2:]).reverse()
So, the key is convert it to a bytearray and reverse it.
In one line:
bytearray.fromhex(hex(5707435436569584202)[2:])[::-1] # bytearray(b'J\xe24OJ\xe24O')
PS: You can treat "bytearray" data like "bytes" and even mix them with b'raw bytes'
Update:
As Will points in coments, you can also manage negative integers:
To make this work with negative integers you need to mask your input with your preferred int type output length. For example, -16 as a little endian uint32_t would be bytearray.fromhex(hex(-16 & (2**32-1))[2:])[::-1], which evaluates to bytearray(b'\xf0\xff\xff\xff')