I am creating a method in Python whereby it will take a number which will form a byte string that will then get sent to the Arduino. However whenever I try, the escape character is always included in the final byte string.
Here is the snippet of the code I am using:
num = 5
my_str = '\\x4' + str(num)
my_str.encode('utf-8')
Result:
b'\\x45'
I tried another method:
num2 = 5
byte1 = b'\\x4'
byte2 = bytes(str(num2), 'ISO-8859-1')
new_byte = byte1 + byte2
new_byte
Result:
b'\\x45'
Trying yet in a different way:
num = 5
u = chr(92) + 'x4' + str(num)
u.encode('ISO-8859-1')
Result:
b'\\x45'
I would like to get the byte string to be b'\x45' without the escape character but not really sure what I have missed. I will appreciate any pointers on how I can achieve this.
Your problem is that you have already escaped the backslash. It is not recommended to construct a literal using an unknown variable, especially if there's a simpler way, which there is:
def make_into_bytes(n):
return bytes([64 + n])
print(make_into_bytes(5))
This outputs
b'E'
Note that this isn't a bug, as this is simply the value of 0x45:
>>> b'\x45'
b'E'
The way this function works is basically just doing it by hand. Prepending '4' to a hex string (of length 1) is the same as adding 4 * 16 to it, which is 64. I then construct a bytes object out of this. Note that I assume n is an integer, as in your code. If n should be a digit like 'a', this would be the integer 10.
If you want it to work on hex digits, rather than on integer digits, you would need to change it to this:
def make_into_bytes(n):
return bytes([64 + int(n, 16)])
print(make_into_bytes('5'))
print(make_into_bytes('a'))
with output
b'E'
b'J'
This quite simply converts the digit from base 16 first.
You can use the built-in function chr() to convert an integer to the corresponding character:
>>> chr(0x40 + 5)
'E'
Alternatively, if you just one to get the n-th letter of the alphabet, it might be more readable to use str.ascii_uppercase
>>> string.ascii_uppercase[5 - 1]
'E'
Note that the results in this answer are strings in Python 3, not bytes objects. Simply calling .encode() on them will convert them to bytes.
Related
I'm trying to convert an integer to binary using the bin() function in Python. However, it always removes the leading zeros, which I actually need, such that the result is always 8-bit:
Example:
bin(1) -> 0b1
# What I would like:
bin(1) -> 0b00000001
Is there a way of doing this?
Use the format() function:
>>> format(14, '#010b')
'0b00001110'
The format() function simply formats the input following the Format Specification mini language. The # makes the format include the 0b prefix, and the 010 size formats the output to fit in 10 characters width, with 0 padding; 2 characters for the 0b prefix, the other 8 for the binary digits.
This is the most compact and direct option.
If you are putting the result in a larger string, use an formatted string literal (3.6+) or use str.format() and put the second argument for the format() function after the colon of the placeholder {:..}:
>>> value = 14
>>> f'The produced output, in binary, is: {value:#010b}'
'The produced output, in binary, is: 0b00001110'
>>> 'The produced output, in binary, is: {:#010b}'.format(value)
'The produced output, in binary, is: 0b00001110'
As it happens, even for just formatting a single value (so without putting the result in a larger string), using a formatted string literal is faster than using format():
>>> import timeit
>>> timeit.timeit("f_(v, '#010b')", "v = 14; f_ = format") # use a local for performance
0.40298633499332936
>>> timeit.timeit("f'{v:#010b}'", "v = 14")
0.2850222919951193
But I'd use that only if performance in a tight loop matters, as format(...) communicates the intent better.
If you did not want the 0b prefix, simply drop the # and adjust the length of the field:
>>> format(14, '08b')
'00001110'
>>> '{:08b}'.format(1)
'00000001'
See: Format Specification Mini-Language
Note for Python 2.6 or older, you cannot omit the positional argument identifier before :, so use
>>> '{0:08b}'.format(1)
'00000001'
I am using
bin(1)[2:].zfill(8)
will print
'00000001'
When using Python >= 3.6, you can use f-strings with string formatting:
>>> var = 23
>>> f"{var:#010b}"
'0b00010111'
Explanation:
var the variable to format
: everything after this is the format specifier
# use the alternative form (adds the 0b prefix)
0 pad with zeros
10 pad to a total length off 10 (this includes the 2 chars for 0b)
b use binary representation for the number
You can use the string formatting mini language (Thanks to #Martijn Pieters for the suggestion) idea:
def binary(num, length=8):
return format(num, '#0{}b'.format(length + 2))
Demo:
print(binary(1))
Output:
'0b00000001'
I like python f-string formatting for a little more complex things like using a parameter in format:
>>> x = 5
>>> n = 8
>>> print(f"{x:0{n}b}")
00000101
Here I print variable x with following formatting: I want it to be left-filled with 0 to have length = n, in b (binary) format. See Format Specification Mini-Language from previous answers for more.
Sometimes you just want a simple one liner:
binary = ''.join(['{0:08b}'.format(ord(x)) for x in input])
Python 3
You can use something like this
("{:0%db}"%length).format(num)
You can use zfill:
print str(1).zfill(2)
print str(10).zfill(2)
print str(100).zfill(2)
prints:
01
10
100
I like this solution, as it helps not only when outputting the number, but when you need to assign it to a variable...
e.g. -
x = str(datetime.date.today().month).zfill(2) will return x as '02' for the month of feb.
You can use string.rjust method:
string.rjust(length, fillchar)
fillchar is optional
and for your Question you can write like this
'0b'+ '1'.rjust(8,'0)
so it will be '0b00000001'
I have an external app that appends the length of the packet at the start of the data. Something like the following code:
x = "ABCDE"
x_len = len(x)
y = "GHIJK"
y_len = len(y)
test_string = chr(x_len) + x + chr(y_len) + y
#TODO:perform base64 encoding
In the client side of the code I need to be able to extract x_len and y_len and read x and y accrodingly.
#TODO:perform base64 decoding
x_len = int(test_string[0])
x = test_string[:x_len]
I get the following error:
ValueError: invalid literal for int() with base 10: '\x05'
I assume the argument of int is in hex so I probbaly need to do some decoding before passing to the int. Can someone give me a pointer as to what function to use from decode or if there is any easier way to accomplish this?
You probably want ord(), not int(), since ord() is the opposite operation from chr().
Note that your code will only work for lengths up to 255 since that is the maximum chr() and ord() support.
t="ABCDE"
print reduce(lambda x,y:x+y,[ord(i) for i in t])
#output 335
usage of ord: it is used to convert character to its ascii values ..
in some cases only for alphabets they consider A :1 --- Z:26 in such cases use
ord('A')-64 results 1 since we know ord('A') is 65
I have a string that hold a binary number as a string
string = '0b100111'
I want to have that value not be a string type but a value (pseudo-code)
bin(string) = 0b100111
Any pythoners know an easy way to do this?
It is all part of this code for a Codecademy: (After answer implemented)
def flip_bit(number,n):
if type(number)==type('s'):
number = int(number,2)
mask=(0b1<<n-1)
print bin(mask)
print mask
desired = bin(number^mask)
return desired
flip_bit('0b111', 2)
What about calling int function with base 2?
>>>s = '0b100111'
>>>b = int(s, 2)
>>>print b
39
you can make it binary by putting a b before the quotes:
>>> s = b'hello'
>>> s.decode()
'hello'
I'm afraid that making it as idealised in your question is impossible. As what you want is a a series of characters, it can only be a string (or you could convert it to an integer). But it is still workable as a number with built in functions- for example:
num1 = '0b0110'
num1 = '0b0101'
result = int(num1, 2) + int(num2, 2)
print(bin(result))
The only way you could have that synatx in your code is if that binary number became a name itself. Python only supports the manipulation of numbers in base 10, as it only interprets number inputs in that format. Otherwise it is a string within which numbers cannot be manipulated.
Today I am reading in a file, and extracting information. I've figured out pretty much everything, but for some reason I am having a very, very annoying problem! I read in an entire line and use the .split() command to break the 'sentence' into 'words' right? And then I alias the 'words' as such:
startAddress = line[ 0 ]
length = line[ 2 ].strip( "(" ).strip( ")" )
...
endAddress = startAddress + length
Note: I strip the length because in the data file it is encased with () which, later, cause problems when I load it into a .csv file because () are used as negatives.
Anyways, if I were to have 0x00230008 be the start address and (4) be the length, my program makes 0x002300084 be the end address instead of 0x00230008C, but if I do hex(length) or hex(startAddress) or even hex(str(length) or hex(str(startAddress)) it throws an error saying hex numbers cannot be converted into hex. Likewise I cannot convert them into integers, either.
Really, all I need to do is add the starting address (which is in Hex, but reads in as a string) and the length (which is in int and reads in as int.) I have tried converting them around, but that didn't work. I also tried the line
endAddress = startAddress + length - 1
which tells me " unsupported operand type(s) for -: 'str' and 'int' " so, I've toyed with it as much as I can, but I'm just not figuring this out. I was thinking of removing the 0x in front of the hex value via strip, but then it reads in as an integer and is incorrect.
The last thing I tried was using line[ 0 ] and line[ 2 ] (with strips) directly to find endAddress, but it gives all the same errors. I tried to force type by stating that startAddress = 0xFFFFFFFF before I assign it equal to line[ 0 ], but that didn't work. So how the heck do I convert a string to a hexidecimal number if it complains that it is hexidecimal when it is not? Or maybe my method of adding them is wrong? Can I use some other adding method?
The biggest confusion for me is that if I try to convert startAddress to a string, and then back into a hexidecimal number, it still complains.
int takes an optional parameter specifying the base of integer you want to convert it into. So you could simple call something like:
proper_int = int(number, 16)
To get a proper representation.
For example:
int("10", 16) = 16
int("F0", 16) = 240
int("0x10", 16) = 16
If you want to add zero padding I would recommend zfill:
"10".zfill(4) = "0010"
You have to parse the string as a base-16 int
>>> int("0x00230008", 16)
2293768
Add the ints
>>> int("0x00230008", 16) + 4
2293772
And convert it back to a hex string:
>>> hex(int("0x00230008", 16) + 4)
'0x23000c'
You'll have to use some string formatting instead of hex to pad it with zeroes, if you need it:
>>> '0x%08x' % (int("0x00230008", 16) + 4)
'0x0023000c'
int() defaults to base-10, so specify the base when calling int on a base-16 string:
>>> int('0x00230008', 16)
2293768
Use int or eval function:
>>> int('0x002300084', 16)
36700292
>>> eval('0x002300084')
36700292
>>> hex(36700292)
'0x2300084'
hex, oct and bin functions all take integers and return string
while int takes string (or unicode), and an optional base argument (default to 10) and returns and integer
I'm trying to create a hex representation of some data that needs to be transmitted (specifically, in ASN.1 notation). At some points, I need to convert data to its hex representation. Since the data is transmitted as a byte sequence, the hex representation has to be padded with a 0 if the length is odd.
Example:
>>> hex2(3)
'03'
>>> hex2(45)
'2d'
>>> hex2(678)
'02a6'
The goal is to find a simple, elegant implementation for hex2.
Currently I'm using hex, stripping out the first two characters, then padding the string with a 0 if its length is odd. However, I'd like to find a better solution for future reference. I've looked in str.format without finding anything that pads to a multiple.
def hex2(n):
x = '%x' % (n,)
return ('0' * (len(x) % 2)) + x
To be totally honest, I am not sure what the issue is. A straightforward implementation of what you describe goes like this:
def hex2(v):
s = hex(v)[2:]
return s if len(s) % 2 == 0 else '0' + s
I would not necessarily call this "elegant" but I would certainly call it "simple."
Python's binascii module's b2a_hex is guaranteed to return an even-length string.
the trick then is to convert the integer into a bytestring. Python3.2 and higher has that built-in to int:
from binascii import b2a_hex
def hex2(integer):
return b2a_hex(integer.to_bytes((integer.bit_length() + 7) // 8, 'big'))
Might want to look at the struct module, which is designed for byte-oriented i/o.
import struct
>>> struct.pack('>i',678)
'\x00\x00\x02\xa6'
#Use h instead of i for shorts
>>> struct.pack('>h',1043)
'\x04\x13'