Format ints into string of hex - python

I need to create a string of hex digits from a list of random integers (0-255). Each hex digit should be represented by two characters: 5 - "05", 16 - "10", etc.
Example:
Input: [0,1,2,3,127,200,255],
Output: 000102037fc8ff
I've managed to come up with:
#!/usr/bin/env python
def format_me(nums):
result = ""
for i in nums:
if i <= 9:
result += "0%x" % i
else:
result += "%x" % i
return result
print format_me([0,1,2,3,127,200,255])
However, this looks a bit awkward. Is there a simpler way?

Just for completeness, using the modern .format() syntax:
>>> numbers = [1, 15, 255]
>>> ''.join('{:02X}'.format(a) for a in numbers)
'010FFF'

''.join('%02x'%i for i in input)

The most recent and in my opinion preferred approach is the f-string:
''.join(f'{i:02x}' for i in [1, 15, 255])
Format options
The old format style was the %-syntax:
['%02x'%i for i in [1, 15, 255]]
The more modern approach is the .format method:
['{:02x}'.format(i) for i in [1, 15, 255]]
More recently, from python 3.6 upwards we were treated to the f-string syntax:
[f'{i:02x}' for i in [1, 15, 255]]
Format syntax
Note that the f'{i:02x}' works as follows.
The first part before : is the input or variable to format.
The x indicates that the string should be hex. f'{100:02x}' is '64', f'{100:02d}' (decimal) is '100' and f'{100:02b}' (binary) is '1100100'.
The 02 indicates that the string should be left-filled with 0's to minimum length 2. f'{100:02x}' is '64' and f'{100:30x}' is ' 64'.
See pyformat for more formatting options.

Python 2:
>>> str(bytearray([0,1,2,3,127,200,255])).encode('hex')
'000102037fc8ff'
Python 3:
>>> bytearray([0,1,2,3,127,200,255]).hex()
'000102037fc8ff'

Yet another option is binascii.hexlify:
a = [0,1,2,3,127,200,255]
print binascii.hexlify(bytes(bytearray(a)))
prints
000102037fc8ff
This is also the fastest version for large strings on my machine.
In Python 2.7 or above, you could improve this even more by using
binascii.hexlify(memoryview(bytearray(a)))
saving the copy created by the bytes call.

Similar to my other answer, except repeating the format string:
>>> numbers = [1, 15, 255]
>>> fmt = '{:02X}' * len(numbers)
>>> fmt.format(*numbers)
'010FFF'

Starting with Python 3.6, you can use f-strings:
>>> number = 1234
>>> f"{number:04x}"
'04d2'

a = [0,1,2,3,127,200,255]
print str.join("", ("%02x" % i for i in a))
prints
000102037fc8ff
(Also note that your code will fail for integers in the range from 10 to 15.)

From Python documentation. Using the built in format() function you can specify hexadecimal base using an 'x' or 'X'
Example:
x= 255
print('the number is {:x}'.format(x))
Output:
the number is ff
Here are the base options
Type
'b' Binary format. Outputs the number in base 2.
'c' Character. Converts the integer to the corresponding unicode character before printing.
'd' Decimal Integer. Outputs the number in base 10.
'o' Octal format. Outputs the number in base 8.
'x' Hex format. Outputs the number in base 16, using lower- case letters for the digits above 9.
'X' Hex format. Outputs the number in base 16, using upper- case letters for the digits above 9.
'n' Number. This is the same as 'd', except that it uses the current locale setting to insert the appropriate number separator characters.
None The same as 'd'.

With python 2.X, you can do the following:
numbers = [0, 1, 2, 3, 127, 200, 255]
print "".join(chr(i).encode('hex') for i in numbers)
print
'000102037fc8ff'

Example with some beautifying, similar to the sep option available in python 3.8
def prettyhex(nums, sep=''):
return sep.join(f'{a:02x}' for a in nums)
numbers = [0, 1, 2, 3, 127, 200, 255]
print(prettyhex(numbers,'-'))
output
00-01-02-03-7f-c8-ff

Using python string format() this can be done.
Code:
n = [0,1,2,3,127,200,255]
s = "".join([format(i,"02X") for i in n])
print(s)
Output:
000102037FC8FF

Related

Swap hex digit pairs in bytes

I have a binary hex string, for example: b'\x914\x05\x11\x11\x95h\xf5' (the f is a filler in this case), and the expected result would be b'\x914\x05\x11\x11\x95h\xf5' → 91340511119568F5 → 19435011115986515.
To do this with the string and a loop is probably not the best solution (there are million on records), what would be a better way?
Edit: Forgot to mention the f is just a filler added from the server (network switch) to provide an even number for the switching (as mentioned by mkrieger)
What you have is a bytes object. When iterating over it you get integer values:
>>> s = b'\x914\x05\x11\x11\x95h\xf5'
>>> list(s) # equivalent to [b for b in s]
[145, 52, 5, 17, 17, 149, 104, 245]
To swap the two "nibbles" (the two 4-bit halves) of a byte, you can use bitwise operations, given that the byte is represented by its integer value. To select the higher-valued nibble, use a bit mask 0xF0 with bitwise and (&), and to select the lower-valued nibble, use 0x0F. Then shift them by 4 bits in the respective directions and combine them again with bitwise or (|):
def swap_nibbles(b: int) -> int:
return ((b & 0xF0) >> 4) | ((b & 0x0F) << 4)
Now you can do this for all bytes in s to get a list of byte values with swapped nibbles:
>>> swapped_nibbles = [swap_nibbles(b) for b in s]
# [25, 67, 80, 17, 17, 89, 134, 95]
Now you just need to reassemble these numbers to your desired result. I'm not entirely sure what exactly you want, so here are some options:
To get another bytes object: Just use the bytes constructor.
>>> bytes(swapped_nibbles)
b'\x19CP\x11\x11Y\x86_'
To get an integer: Use the int.from_bytes constructor with big-endian byte order.
>>> int.from_bytes(swapped_nibbles, byteorder='big')
1820386708623558239 # == 0x194350111159865F
To get a hex string: Use hex on the above integer, or build it from the individual bytes:
>>> ''.join(f'{b:02X}' for b in swapped_nibbles)
'194350111159865F'
It's not clear to me what exactly the rules are for excluding the last F from the result, so you would have to add this logic yourself somehow.

Error in converting array with decimals into array with binaries in python

I am trying to covert and array filed with decimals from 0 to 63 , x=[0 1 2 ... 63] into an array with the equal binaries, but I get the following error:
"invalid literal for int() with base 10: '0b0'". My code is the following (in Python) :
g=np.arange(0,64,1)
for x in range(0,64,1):
g[x]=bin(g[x])
I am new to python, so if anyone can find my mistake (logic or syntax) I would appreciate any help. extra: Is there any way to make the binaries 6 bits that get put in the array?
Using Python 3:
Initialize the g array first, then append it in the loop.
g = '{0:06b}'.format(0)
for x in range(1,64,1):
g=np.append(g,'{0:06b}'.format(x))
print(g)
extra: Python is very well documented
hth
You will have to store them as strings representing binary numbers.
>>> x=0x1011 # hex
>>> x
4113 #just another number under the hood
>>> x=0b1011
>>> x
11
>>> x=str(0b1011)
>>> x
'11'
>>> x=str(bin(11))
>>> x
'0b1011'
>>>
bin_list = []
for each in range(64):
bin_rep = str(bin(each))
bin_rep = bin_rep[:2] + bin_rep[2:].zfill(6)
bin_list.append(bin_rep)
print(bin_list)
Not as concise as another comment but possibly more easy to follow for someone new to Python... Hope this helps!

Converting hexadecimal value to decimal in Python

I just started working with hexadecimal values in python and am a bit surprised with what I just encountered. I expected the following code to first print a hexadecimal string, and then a decimal value.
Input:
n = 0x8F033CAE74F88BA10D2BEA35FFB0EDD3
print('Hex value for n is:', n)
print('Dec value for n is:', int(str(n), 16))
Output:
Hex value for n is: 190096411054295805012706659640261275091
Dec value for n is: 8921116140846515089057635273465667902228615313
How is it possible that 2 different different numbers are shown? I expected the first number to be a hexadecimal string and the second it's decimal equivalent, what is this second value in this case?
0x is a way to input an integer with an hexadecimal notation.
>>> n = 0x8F033CAE74F88BA10D2BEA35FFB0EDD3
This hexadecimal notation is forgotten directly after instantiation, though:
>>> n
190096411054295805012706659640261275091
>>> str(n)
'190096411054295805012706659640261275091'
So when you call int(str(n), 16), Python interprets '190096411054295805012706659640261275091' as an hexadecimal number:
>>> int(str(n), 16)
8921116140846515089057635273465667902228615313
You need to input the original hex string:
>>> int("8F033CAE74F88BA10D2BEA35FFB0EDD3", 16)
190096411054295805012706659640261275091
or use hex:
>>> int(hex(n), 16)
190096411054295805012706659640261275091

OR element wise operation over two binary lists

I have the following code of two binary lists and I want to obtain a resulting list in which the element i will be the OR operation applied to the i elements of the two lists:
from operator import ior
l_0 = [01100]
l_1 = [11000]
print map(ior, l_0, l_1)
And I was expecting a result of [11100], but the result is:
[11000]
I have checked ior operator and the documentation says that it performs the operation:
a = ior(a, b) is equivalent to a |= b
So I tried the following to check as well:
print ior(0,0)
print ior(1,0)
print ior(0,1)
print ior(1,1)
Getting as results:
0
1
1
1
Which makes sense, but doesn't coincide with the result obtained in the 3rd position of the lists. I don't understand why the result of the map operation of above is not [11100]. I am missing something here and I hope that you can throw some light on it.
[11000] (for example) is not a list of five binary digits, it's a list of one decimal number, 11000.
Similarly, 01100 is a single octal number equal to 576 decimal, so:
11000d = 0010101011111000b
01100o = 576d = 0000001001000000b
-----------------
perform or: 0010101011111000b = 11000d
That's why you're getting 11000 as the answer, exactly the same as if you'd done:
[l_0[i] | l_1[i] for i in range(len(l_0))]
If you want to process a list of five binary digits, that would be something like:
>>> l_0 = [0,1,1,0,0]
>>> l_1 = [1,1,0,0,0]
>>> [l_0[i] | l_1[i] for i in range(len(l_0))]
[1, 1, 1, 0, 0]
01100 is octal representation (576 in decimal). 11000 is decimal representation. They are not binary representations.
To represent binary, prefix them with 0b:
[`01100`, `11000`]
And to get binary representation from the number use bin:
bin(num)
or
'{:b}'.format(num)

Binary to Decimal (mathematics way)

If there is an binary number:10011100
It is 156 in decimal.
I want to use mathematics way to make binary to decimal.
For example:
binary: 10011100
the first number is 1: 2**7
the forth number is 1: 2**4
the fifth number is 1: 2**3
the sixth number is 1: 2**2
then 2**7+2**4+2**3+2**2 = 156
I think, I need to use string.find() method.
>>> my_str = '10011100'
>>> my_str = my_str[::-1]
>>> print(my_str)
00111001
>>> my_str.find('1')
2
>>>
I just can find the first '1'.
How to find all the index of '1'?
Why do you want to retrieve the indexes? You can simply iterate over the bits like this:
num = sum(2**i for i, bit in enumerate(my_str) if bit == '1')
Anyway, you can get the indexes like this if you prefer two separate steps:
indexes = [i for i, bit in enumerate(my_str) if bit == '1']
num = sum(2**i for i in indexes)
You may also check the built-in int() function that takes a base argument:
int(x[, base]) -> integer
In [1]: my_str = '10011100'
In [2]: int(my_str,2)
Out[2]: 156
Binary Number:
If you are considering why binary number has a base 2 always well the answer is a binary number is expressed in the base-2 because it uses only two symbols: typically "0" (zero) and "1" (one). eg 10011100 (only "zero" and "one" used)
If there is an binary number:10011100 It is 156 in decimal.
The Binary number here is 10011100 it always has a base 2 even if it is not written 10011100 is same as 10011100 base 2
Convert Binary to Decimal
We start from the most right number and move toward left
Multi the binary number with 2 that is the base and the power(^) keeps increasing by 1
(0*2^0)+(0*2^1)+(1*2^2)+(1*2^3)+(1*2^4)+(0*2^5)+(0*2^6)+(1*2^7)
=156
If you want to under stand more clearly here is a link
[https://www.mathwarehouse.com/non-decimal-bases/convert-binary-to-decimal.php?ref=driverlayer.com][1]

Categories

Resources