I am facing a challenge to create a bytes list in python. I just want to convert the int list into bytes list as mentioned in expected result. The problem statement is that I want to send the expected output to the serial device connected to the com port and with current output the serial device is not encouraging the '\\' as a separator. Please suggest me the correct way to handle the '\' in a list of bytes.
cmdlist = [2, 12, 1, 1, 1, 0, 0, 1, 3, 7, 42, 101, 85, 18]
#Convert CMD list to Hex List
for i in range(len(cmdlist)):
cmdlist[i] = hex(cmdlist[i])
f_cmdList = ''
#Convert hex CMD list to string List
for i in range(len(cmdlist)):
f_cmdList += '\\' + (cmdlist[i])
Final_cmdlist = (bytes(f_cmdList,'utf-8'))
print(Final_cmdlist)
Current output : b'\\0x2\\0xc\\0x1\\0x1\\0x1\\0x0\\0x0\\0x1\\0x3\\0x7\\0x2a\\0x65\\0x55\\0x12'
Expected output : b'\0x2\0xc\0x1\0x1\0x1\0x0\0x0\0x1\0x3\0x7\0x2a\0x65\0x55\0x12'
Thank You !
You can convert a list to bytes simply by using the bytes constructor. Your method is trying to create a string that contains the string representation of a byte array, which won't work when sent to the serial device:
>>> cmdlist = [2, 12, 1, 1, 1, 0, 0, 1, 3, 7, 42, 101, 85, 18]
>>> bytes(cmdlist)
b'\x02\x0c\x01\x01\x01\x00\x00\x01\x03\x07*eU\x12'
You get what you say you expect if you replace your
f_cmdList += '\\' + (cmdlist[i])
with this:
f_cmdList += '\0' + cmdlist[i][1:]
Still not convinced that you really want that, though.
I have a long 1-dimensional list of integer 1's and 0's, representing 8-bit binary bytes. What is a neat way to create a new list from that, containing the integer bytes.
Being familiar with C, but new to Python, I've coded it in the way I'd do it with C: an elaborate structure that loops though each bit. However, I'm aware that the whole point of Python over C is that such things can usually be done compactly and elegantly, and that I should learn how to do that. Maybe using list comprehension?
This works, but suggestions for a more "Pythonic" way would be appreciated:
#!/usr/bin/env python2
bits = [1,0,0,1,0,1,0,1,0,1,1,0,1,0,1,1,1,1,1,0,0,1,1,1]
bytes = []
byt = ""
for bit in bits:
byt += str(bit)
if len(byt) == 8:
bytes += [int(byt, 2)]
byt = ""
print bytes
$ bits-to-bytes.py
[149, 107, 231]
You can slice the list into chunks of 8 elements and map the subelements to str:
[int("".join(map(str, bits[i:i+8])), 2) for i in range(0, len(bits), 8)]
You could split it up into two parts mapping and joining once:
mapped = "".join(map(str, bits))
[int(mapped[i:i+8], 2) for i in range(0, len(mapped), 8)]
Or using iter and borrowing from the grouper recipe in itertools:
it = iter(map(str, bits))
[int("".join(sli), 2) for sli in zip(*iter([it] * 8))]
iter(map(str, bits)) maps the content of bits to str and creates an iterator, zip(*iter([it] * 8)) groups the elements into groups of 8 subelements.
Each zip(*iter.. consumes eight subelements from our iterator so we always get sequential groups, it is the same logic as the slicing in the first code we just avoid the need to slice.
As Sven commented, for lists not divisible by n you will lose data using zip similarly to your original code, you can adapt the grouper recipe I linked to handle those cases:
from itertools import zip_longest # izip_longest python2
bits = [1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1,1,0]
it = iter(map(str, bits))
print( [int("".join(sli), 2) for sli in izip_longest(*iter([it] * 8),fillvalue="")])
[149, 107, 231, 2] # using just zip would be [149, 107, 231]
The fillvalue="" means we pad the odd length group with empty string so we can still call int("".join(sli), 2) and get correct output as above where we are left with 1,0 after taking 3 * 8 chunks.
In your own code bytes += [int(byt, 2)] could simply become bytes.append(int(byt, 2))
Padraic's solution is good; here's another way to do it:
from itertools import izip_longest
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# Taken from itertools recipes
# https://docs.python.org/2/library/itertools.html#recipes
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
bits = [1, 0, 0, 1, 0, 1, 0, 1,
0, 1, 1, 0, 1, 0, 1, 1,
1, 1, 1, 0, 0, 1, 1, 1]
byte_strings = (''.join(bit_group) for bit_group in grouper(map(str, bits), 8))
bytes = [int(byte_string, 2) for byte_string in byte_strings]
print bytes # [149, 107, 231]
Since you start from a numeric list you might want to avoid string manipulation. Here there are a couple of methods:
dividing the original list in 8 bits chunks and computing the decimal value of each byte (assuming the number of bits is a multiple of 8); thanks to Padraic Cunningham for the nice way of dividing a sequence by groups of 8 subelements;
bits = [1,0,0,1,0,1,0,1,0,1,1,0,1,0,1,1,1,1,1,0,0,1,1,1]
[sum(b*2**x for b,x in zip(byte[::-1],range(8))) for byte in zip(*([iter(bits)]*8))]
using bitwise operators (probably more efficient); if the number of bits is not a multiple of 8 the code works as if the bit sequence was padded with 0s on the left (padding on the left often makes more sense than padding on the right, because it preserves the numerical value of the original binary digits sequence)
bits = [1,0,0,1,0,1,0,1,0,1,1,0,1,0,1,1,1,1,1,0,0,1,1,1]
n = sum(b*2**x for b,x in zip(bits[::-1],range(len(bits)))) # value of the binary number represented by 'bits'
# n = int(''.join(map(str,bits)),2) # another way of finding n by means of string manipulation
[(n>>(8*p))&255 for p in range(len(bits)//8-(len(bits)%8==0),-1,-1)]
I'm writing a program in Linux which reads and distinguish inputs from two USB devices(two barcode readers) which simulates a keyboard.
I've already can read inputs from USB, but it happens before OS translate keycode in a charactere.
For example, when I read 'a' i got 24, 'b' 25, etc....
For example, when I read 'a' i got 4, 'b' 5, etc....
Is there any way to convert that code in a char without manual mapping?
Some output exemples:
KEYPRESS = a output = array('B', [0, 0, 4, 0, 0, 0, 0, 0])
KEYPRESS = SHIFT + a output = array('B', [2, 0, 4, 0, 0, 0, 0, 0])
KEYPRESS = 1 output = array('B', [0, 0, 30, 0, 0, 0, 0, 0])
KEYPRESS = ENTER output = array('B', [0, 0, 81, 0, 0, 0, 0, 0])
thx!
Use the chr function. Python uses a different character mapping (ASCII) from whatever you're receiving though, so you will have to add 73 to your key values to fix the offset.
>>> chr(24 + 73)
'a'
>>> chr(25 + 73)
'b'
I've already can read inputs from USB, but it happens before OS
translate keycode in a charactere.
The problem seems to me in your interface or the driver program.
In ASCII 'a' is supposed to have ordinal value 97 whose binary representation is 0b1100001, where as what you are receiving is 27 whose binary representation is 0b11000, similarly for 'b' you were supposed to received '0b1100010' instead you received 25 which is 0b11001. Check your hardware to determine if the 1st and the 3rd bit is dropped from the input.
What you are receiving is USB scan code. I do not think there is a third party python library to do the conversion for you. I would suggest you to refer any of the USB Scan Code Table and from it, create a dictionary of USB Scan Code vs the corresponding ASCII.
In my c1.txt file, i have something like
var0 = '0x000000000000004080'
And in my python mail file:
def getVarFromFile(filename):
import imp
f = open(filename)
global data
data = imp.load_source('data', '', f)
f.close()
getVarFromFile('c1.txt')
The var0 is a 72-bit variable, and in my python file, I want to assign that to 12 variable with 6-bit for each, how can I do that?
Since var0 is a hex variable, seems I can't do
x = int(data.var1) & 0x3F
Thanks
I think all you need to do in your last line is provide a base for the integer conversion:
values_from_hex = int(data.var1, 16)
Then you can divide the value up into your 6-bit values (least significant bits first):
six_bit_values = [values_from_hex >> i*6 & 0x3f for i in range(12)]
For a value of '0x000000000000004080', this gets [0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0].
I append to tcp packet unsinged long long with value 4 and additional unsigned long long with value 8616616 ( i dont remember the second value ).
I do it in c on ubuntu 32 , so unsigned long long is 8 bytes.
I sniff the packet with scapy and print the padding.load .
In the output i see symbols that i dont undesrtand the meaning of them - g, |
In additional the load should be 16 bytes , but i dont see 16 bytes.
If i append only one unsigned long long i get 8 bytes and i dont see these symbols
>>> pkt = sniff(count=2,filter="tcp")
>>> raw = pkt[1].sprintf('%Padding.load%')
>>> raw
"'\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00g\\xc4|\\x00\\x00\\x00\\x00\\x00'"
>>> print raw
'\x04\x00\x00\x00\x00\x00\x00\x00g\xc4|\x00\x00\x00\x00\x00'
When you are printing out the value of raw, python interprets all bytes that have a value greater than 31 as ASCII characters. When you see g the value for that byte is equal to 103, likewise | is the ASCII code for 124. For characters above 127, python uses a different representation which is why you have \xc4 in your output, the value of that byte is 196.
The actual value of each of the bytes in raw is:
[4, 0, 0, 0, 0, 0, 0, 0, 103, 196, 124, 0, 0, 0, 0, 0]
Which is 16 bytes long.
You can test this by converting the value of each byte back into a character:
>>> values = [4, 0, 0, 0, 0, 0, 0, 0, 103, 196, 124, 0, 0, 0, 0, 0]
>>> as_characters = ''.join(chr(c) for c in values)
>>> as_characters
'\x04\x00\x00\x00\x00\x00\x00\x00g\xc4|\x00\x00\x00\x00\x00'
>>> len(as_characters)
16
I think what you have for raw has had each of the bytes escaped. In my example, when I output as_characters I only see a single backslash, you have two. You may need to use something like pkt[1].sprintf('%Padding.loadr%') to get the non escaped version.