Convert Hexadecimal string to long python - python

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.

Related

Convert a list of ints to a float

I am trying to convert a number stored as a list of ints to a float type. I got the number via a serial console and want to reassemble it back together into a float.
The way I would do it in C is something like this:
bit_data = ((int16_t)byte_array[0] << 8) | byte_array[1];
result = (float)bit_data;
What I tried to use in python is a much more simple conversion:
result = int_list[0]*256.0 + int_list[1]
However, this does not preserve the sign of the result, as the C code does.
What is the right way to do this in python?
UPDATE:
Python version is 2.7.3.
My byte array has a length of 2.
in the python code byte_array is list of ints. I've renamed it to avoid misunderstanding. I can not just use the float() function because it will not preserve the sign of the number.
I'm a bit confused by what data you have, and how it is represented in Python. As I understand it, you have received two unsigned bytes over a serial connection, which are now represented by a list of two python ints. This data represents a big endian 16-bit signed integer, which you want to extract and turn into a float. eg. [0xFF, 0xFE] -> -2 -> -2.0
import array, struct
two_unsigned_bytes = [255, 254] # represented by ints
byte_array = array.array("B", two_unsigned_bytes)
# change above to "b" if the ints represent signed bytes ie. in range -128 to 127
signed_16_bit_int, = struct.unpack(">h", byte_array)
float_result = float(signed_16_bit_int)
I think what you want is the struct module.
Here's a round trip snippet:
import struct
sampleValue = 42.13
somebytes = struct.pack('=f', sampleValue)
print(somebytes)
result = struct.unpack('=f', somebytes)
print(result)
result may be surprising to you. unpack returns a tuple. So to get to the value you can do
result[0]
or modify the result setting line to be
result = struct.unpack('=f', some bytes)[0]
I personally hate that, so use the following instead
result , = struct.unpack('=f', some bytes) # tuple unpacking on assignment
The second thing you'll notice is that the value has extra digits of noise. That's because python's native floating point representation is double.
(This is python3 btw, adjust for using old versions of python as appropriate)
I am not sure I really understand what you are doing, but I think you got 4 bytes from a stream and know them to represent a float32 value. The way you handling this suggests big-endian byte-order.
Python has the struct package (https://docs.python.org/2/library/struct.html) to handle bytestreams.
import struct
stream = struct.pack(">f", 2/3.)
len(stream) # 4
reconstructed_float = struct.unpack(">f", stream)
Okay, so I think int_list isn't really just a list of ints. The ints are constrained to 0-255 and represent bytes that can be built into a signed integer. You then want to turn that into a float. The trick is to set the sign of the first byte properly and then procede much like you did.
float((-(byte_array[0]-127) if byte_array[0]>127 else byte_array[0])*256 + byte_array[1])

Convert 64-bits floating-point format string to floating-point number

I have a bunch of 64-bit floating-point-format strings, and I have to convert them into floating-point numbers. I know what the format looks like, but I’m wondering whether there’s a built-in function can fulfill this job directly, as in:
convertToFloat(C06FCA5E35000000) --> -254.324
convertToFloat(405F7D70A4000000) --> +125.96
I know how to convert these bit patterns to numbers manually, but it needs a lot of bit shifting. Is there a better way?
I modified 'C06FCA5E35000000' to '\xC0\x6F\xCA\x5E\x35\x00\x00\x00', and stored it to myString.
>>>print (myString)
\xC0\x6F\xCA\x5E\x35\x00\x00\x00
>>>d = struct.unpack('>d', myString)
d = struct.unpack('>d', myString)
struct.error: unpack requires a string argument of length 8
Why did it happened?
I didn't use binascii.a2b_hex or binascii.b2a_hex, beacuse it converts 'A' to '41' or '41' to 'A'. Both are not what I want. Right?
>>>print len('\xC0\x6F\xCA\x5E\x35\x00\x00\x00')
8
>>>print len(myString)
32
Now I know why it happened, but I still don't know how to solve the situation.
You can use struct.unpack. >d is a big-endian double; see help(struct) for more!
import struct
d, = struct.unpack('>d', b'\xc0\x6f\xca\x5e\x35\x00\x00\x00')
print(d)
# -254.32399988174438
If your string is really 'C06FCA5E35000000', you can convert it first into bytes using binascii.a2b_hex.

Python 2,3 Convert Integer to "bytes" Cleanly

The shortest ways I have found are:
n = 5
# Python 2.
s = str(n)
i = int(s)
# Python 3.
s = bytes(str(n), "ascii")
i = int(s)
I am particularly concerned with two factors: readability and portability. The second method, for Python 3, is ugly. However, I think it may be backwards compatible.
Is there a shorter, cleaner way that I have missed? I currently make a lambda expression to fix it with a new function, but maybe that's unnecessary.
Answer 1:
To convert a string to a sequence of bytes in either Python 2 or Python 3, you use the string's encode method. If you don't supply an encoding parameter 'ascii' is used, which will always be good enough for numeric digits.
s = str(n).encode()
Python 2: http://ideone.com/Y05zVY
Python 3: http://ideone.com/XqFyOj
In Python 2 str(n) already produces bytes; the encode will do a double conversion as this string is implicitly converted to Unicode and back again to bytes. It's unnecessary work, but it's harmless and is completely compatible with Python 3.
Answer 2:
Above is the answer to the question that was actually asked, which was to produce a string of ASCII bytes in human-readable form. But since people keep coming here trying to get the answer to a different question, I'll answer that question too. If you want to convert 10 to b'10' use the answer above, but if you want to convert 10 to b'\x0a\x00\x00\x00' then keep reading.
The struct module was specifically provided for converting between various types and their binary representation as a sequence of bytes. The conversion from a type to bytes is done with struct.pack. There's a format parameter fmt that determines which conversion it should perform. For a 4-byte integer, that would be i for signed numbers or I for unsigned numbers. For more possibilities see the format character table, and see the byte order, size, and alignment table for options when the output is more than a single byte.
import struct
s = struct.pack('<i', 5) # b'\x05\x00\x00\x00'
You can use the struct's pack:
In [11]: struct.pack(">I", 1)
Out[11]: '\x00\x00\x00\x01'
The ">" is the byte-order (big-endian) and the "I" is the format character. So you can be specific if you want to do something else:
In [12]: struct.pack("<H", 1)
Out[12]: '\x01\x00'
In [13]: struct.pack("B", 1)
Out[13]: '\x01'
This works the same on both python 2 and python 3.
Note: the inverse operation (bytes to int) can be done with unpack.
I have found the only reliable, portable method to be
bytes(bytearray([n]))
Just bytes([n]) does not work in python 2. Taking the scenic route through bytearray seems like the only reasonable solution.
Converting an int to a byte in Python 3:
n = 5
bytes( [n] )
>>> b'\x05'
;) guess that'll be better than messing around with strings
source: http://docs.python.org/3/library/stdtypes.html#binaryseq
In Python 3.x, you can convert an integer value (including large ones, which the other answers don't allow for) into a series of bytes like this:
import math
x = 0x1234
number_of_bytes = int(math.ceil(x.bit_length() / 8))
x_bytes = x.to_bytes(number_of_bytes, byteorder='big')
x_int = int.from_bytes(x_bytes, byteorder='big')
x == x_int
from int to byte:
bytes_string = int_v.to_bytes( lenth, endian )
where the lenth is 1/2/3/4...., and endian could be 'big' or 'little'
form bytes to int:
data_list = list( bytes );
When converting from old code from python 2 you often have "%s" % number this can be converted to b"%d" % number (b"%s" % number does not work) for python 3.
The format b"%d" % number is in addition another clean way to convert int to a binary string.
b"%d" % number

Convert decimal int to little endian string ('\x##\x##...')

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

Python BCD splitting nibbles and concatenation 2 ints

I feel like a complete tool for posting this, it is so basic and I cant believe I have wasted the last two days on this problem. I've tried all the solutions I can find on this (seriously, I will show you my internet history) but to no avail. Here is the problem:
I am parsing a serial string in from a uC. It is 52 bytes long and contains a lot of different variables of data. The data in encoded in packed binary coded decimal.
Ex: .....blah.....0x01 0x5E .....blah
015E hex gives 350 decimal. This is the value I want. I am reading in the serial string just fine, I used binascii.hexifiy to print the bytes to ensure it is corrent. I use
data = ser.read()
and placed the data in an array if an newline is not received. I have tried making the array a bytearray, list, anything that I could find, but none work.
I want to send the required two byte section to a defined method.
def makeValue(highbyte, lowbyte)
When I try to use unpack, join, pack, bit manipulation, string concentation, I keep getting the same problem.
Because 0x01 and 0x5E are not valid int numbers (start of heading and ^ in ASCII), it wont work. It wont even let me join the numbers first because it's not a valid int.
using hex(): hex argument can't be converted to hex.
Joining the strings: invalid literal for int() with base 16: '\x01^'
using int: invalid literal for int() with base 10: '\x01^'
Packing a struct: struct.error: cannot convert argument to integer
Seriously, am I missing something really basic here? All the examples I can find make use of all the functions above perfectly but they specificy the hex numbers '0x1234', or the numbers they are converting are actual ASCII numbers. Please help.
EDIT
I got it, ch3ka set me on the right track, thanks a million!
I don't know why it wouldn't work before but I hex'ed both values
one = binascii.hexlify(line[7])
two = binascii.hexlify(line[8])
makeValue(one, two)`
and then used the char makeValues ch3ka defined:
def makeValue(highbyte, lowbyte)
print int(highbyte, 16)*256 + int(lowbyte, 16)
Thanks again!!!
you are interpreting the values as chars. Feeding chars to int() won't work, you have to feed the values as strings, like so: int("0x5E", 16). What you are attempting is in fact int(chr(int("0x5E", 16)),16), which is int("^",16) and will of course not work.
Do you expect these results?
makevalue('0x01', '0x5E') -> 350 0x15e 0b101011110
makevalue('0xFF', '0x00') -> 65280 0xff00 0b1111111100000000
makevalue('0x01', '0xFF') -> 511 0x1ff 0b111111111
makevalue('0xFF', '0xFF') -> 65535 0xffff 0b1111111111111111
If so, you can use this:
def makeValue(highbyte, lowbyte):
return int(highbyte, 16)*256 + int(lowbyte, 16)
or the IMO more ugly and errorprone:
def makeValue(highbyte, lowbyte):
return int(highbyte+lowbyte[2:], 16) # strips leading "0x" from lowbyte be4 concat

Categories

Resources