I want to xor two hex-format strings in python, like '45' and '4e'. But how do I keep the leading zero if the result is in [0x00, 0x0f]?
hex(int('45', 16) ^ int('4e', 16))
gives '0xb', while I'm expecting '0x0b'.
Thanks in advance.
The easiest method is to use str.format():
>>> '0x{:02x}'.format(0xb)
'0x0b'
For a relatively small number of values (like 0x00-0xff), one practical as well as very efficient method to convert the result into hexadecimal string the way you wish is to build and use a look-up table. The '0x%02x' % vexpression employed in building the table would also be a simple and fairly concise way of converting a single value just once.
>>> HEXDEC = ['0x%02x' % v for v in (x+y for x in range(16) for y in range(16))]
>>> HEXDEC[int('45', 16) ^ int('4e', 16)]
'0x0b'
>>>
The problem here is your expectations from the function hex.
hex() only produces a string presentation for output.
Proof:
>>> hex(2)+hex(15)
'0x20xf'
Which is utter nonsense of course since the string value of hex(2) and the string value of hex(15) are just being appended together.
The solution is to do your arithmetic clear though to the end THEN select how you wish to present the result.
The result of your calculation is 11:
>>> int('45', 16) ^ int('4e', 16)
11
Then format it.
Old way:
>>> '0x%0.2x' % 11
'0x0b'
Newer way:
>>> '0x'+format(11,'02x')
'0x0b'
Or:
>>> '0x{:02x}'.format(11)
'0x0b'
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'
When I do a simple division in Python 3, such as 123000/1000, I get 123.0, or 4/2 I get 2.0. How do I get rid of the trailing zero in Python 3's division?
EDIT:
I don't want just simple integer division. For ex, 1234/1000 should give 1.234.
To be clear, this question is about formatting the output, not internal representation.
Thanks all for your help! The answer came from #vaultah:
>>> f'{2.1:g}'
'2.1'
>>> f'{2.0:g}'
'2'
So just use regular division such as 4/2 and then format the string.
From the docs for 'g': https://docs.python.org/2/library/string.html#format-specification-mini-language
"insignificant trailing zeros are removed from the significand, and the decimal point is also removed if there are no remaining digits following it."
You could use something like this:
def remove_trailing_zeros(x):
return str(x).rstrip('0').rstrip('.')
remove_trailing_zeros(1.23) # '1.23'
remove_trailing_zeros(4.0) # '4
Normally, you would use standard string formatting options like '%2.1f' % number or any of the other many ways to format a string. However, you would then have to specify the amount of digits you want to display but in this case the number of trailing zeros to return is variable. The '%g' format specifier does not have this problem, but uses scientific notation and I don't know if that is what the OP wants.
The above solution converts the number to a "nicely printable string representation" (str(x)), and then removes trailing zeros (.rstrip('0')) and if necessary the remaining trailing period (.rstrip('.')) (to avoid "1." as a result) using standard string methods.
It's "correct" behaviour to have "floats" as a result, and .0 part simply indicates this fact. I think that what matter to you is "representation" of the result in the string. So you should not change actual result and only change the way it's "displayed". Use formatting mini language:
>>> for val in (123000/1000, 4/2, 1234/1000): print(f"{val:g}") # Use "General format" to represent floats
...
123
2
1.234
Mod is an O(1) operation which should add almost no overhead to your actual program. You could make it into a one liner also
x = a//b if not a % b else a/b
If you need to do this kind of thing a lot, make it into a function
def func(a, b):
return a//b if not a % b else a/b
func(10, 2) # out = 5
func(10, 3) # out = 3.333333333
func(1200, 100) # out = 12
func(1234, 1000) # out = 1.234
This works well for me. No scientific notation format for big numbers.
def no_trailing_zero(value: float) -> Union[float, int]:
return int(value) if value % 1 == 0 else float(str(value))
>>> no_trailing_zero(50)
50
>>> no_trailing_zero(50.11)
50.11
>>> no_trailing_zero(50.1100)
50.11
>>> no_trailing_zero(50.0)
50
>>> no_trailing_zero(500000000.010)
500000000.01
>>>
If you can guarantee that you get just a trailing zero, casting to int gets rid of it:
>>> 4/2
2.0
>>> int(4/2)
2
# // => used for integer output
# / => used for double output
x = 100/35 # => 2.857142857142857
y = 100//35 # => 2
z = 100.//35 # => 2.0 # floating-point result if divisor or dividend real
I am trying to take air pressure readings and plot them with their last 2 digits showing. However, when I use modulo:
--> x = 1004
--> x % 100
--> 4
This just generates 4.
How can I display this to show 04 instead of 4?
Thanks!
Try the following:
str(x%100).zfill(2)
If you need it as an int or a float, I don't think this is possible. If it's only for display purposes, convert it to a string and take the last 2 characters:
x = 1004
>>> str(x)[-2:]
'04'
If you just print out a number, it prints it out in its default format. For the number 2, that's obviously going to be 2, not 02.
If you want to specify a custom format, you need to use some form of string formatting. Python has a few ways to do it.
Format Strings
The same Format String Syntax is used by the format function, the str.format method, Formatter subclasses, and (with slight differences that aren't relevant here) f-string literals.
You can specify a width of 2, plus an align of = (meaning numeric alignment—padding is placed after any + or -) and a fill of 0. But there's also a special shortcut, where placing a 0 right before the width means numeric-aligned zero-fill. So:
>>> f"{x % 100:02}"
'02'
>>> format(x % 100, '02')
'02'
>>> '{:02}'.format(x % 100)
'02'
printf-style String Formatting
Python has an older, but still sometimes useful, way to do formatting,1 which more closely matches that of C and similar languages, calling printf-style or %-formatting.
You specify a width of 2, and a flag of 0, which indicates numeric zero-padding, together with a type of d to specify that you want to format the number as a signed integer decimal:
>>> "%02d" % (x % 100,)
'02'
While %-formatting isn't as flexible and powerful as format strings, it can sometimes be simpler to understand (especially if you're used to C or another language), is often faster, and works with bytes as well as str.
Manual string operations
Finally, you can always convert the number to a string and then use string methods on it. For example, you can use the zfill method to zero-fill a string:
>>> str(x % 100).zfill(2)
'02'
… or you can use the rjust method to right-justify it with '0' as a fill character:
>>> str(x % 100).rjust(2, '0')
'02'
In fact, instead of calculating the remainder, you could just convert the whole thing to a string, truncate it, then zero-fill:
>>> str(x)[-2:].zfill(2)
… although this probably won't be what you want is x is, say, -123 (you'll get 23 instead of 77).
1. In fact, it provides two older solutions, the other being template strings, but these aren't useful as often.
The shortest way to do this is '%02d' % (x % 100)
x = 1004
x = x % 100
str(x)
y = len(x)
if y == 0:
end
elif y == 2:
print (x)
elif y == 1:
print ('0'x)
else:
x = str(x)[-2:]
print (x)
In this, I've converted it into a string & calculated the length of the value as 'y'. Using a basic [if elif else] structure I have returned the values in your format, but as strings.
It is unclear what you wanted to use these values for because if you want them to represent figures you will probably need to edit the settings of whatever output application you are using. An alternative solution would be to use the value for 'x' as being different to the string so that the number value can still be used regardless of the way it is displayed when printing. wink, wink.
You could use string formatting too.
ans = 1004 % 100
format(ans, '03d')
More information about String formatting can be found here: https://pyformat.info/
No modulo, no zfill.
"{:02d}".format(12345)[-2:]
#> 45
"{:02d}".format(0)[-2:]
#> 00
"{:02d}".format(-9876)[-2:]
#> 76
"{:02d}".format(-1)[-2:]
#> -1
Your first step to use the modulus operator to find the two-least significant digits is correct.
Then you'll want to use a format string to pad your result when printing it. See: Python format Integer into fixed length strings
So I have a problem where I want to xor various hex strings, convert them to regular english strings, then re-convert them to hex strings. I'm not really familiar with working with hex or xor in any meaningful way, however. Do I need to convert the hex to binary or unicode before I perform a bitwise xor operation? If so, how do I retrieve the hex values once that is done? I've been looking into using str.encode('hex') and str.decode('hex'), but I keep getting errors saying that I am using non-hexadecimal characters. In short, I'm totally lost.
Python has an XOR operator for integers: ^. Here's how you could use it:
>>> hex(int("123abc", 16) ^ int("def456", 16))
'0xccceea'
EDIT: testing with long hex strings as per your comment:
>>> def hexor(hex1, hex2):
... """XOR two hex strings."""
... xor = hex(int(hex1, 16) ^ int(hex2, 16))
... return xor[2:].rstrip("L") # get rid of "0x" and maybe "L"
...
>>> import random
>>> a = "".join(random.choice("0123456789abcdef") for i in range(200))
>>> b = "".join(random.choice("0123456789abcdef") for i in range(200))
>>> a
'8db12de2f49f092620f6d79d6601618daab5ec6747266c2eea29c3493278daf82919aae6a72
64d4cf3dffd70cb1b6fde72ba2a04ac354fcb871eb60e088c2167e73006e0275287de6fc6133
56e44d7b0ff8378a0830d9d87151cbf3331382b096f02fd72'
>>> b
'40afe17fa8fbc56153c78f504e50a241df0a35fd204f8190c0591eda9c63502b41611aa9ac2
27fcd1a9faea642d89a3a212885711d024d2c973115eea11ceb6a57a6fa1f478998b94aa7d3e
993c04d24a0e1ac7c10fd834de61caefb97bcb65605f06eae'
>>> hexor(a, b)
'cd1ecc9d5c64cc47733158cd2851c3cc75bfd99a6769edbe2a70dd93ae1b8ad36878b04f0b0
43281e94053d689c3f5e45392af75b13702e7102fa3e0a990ca0db096fcff60db1f672561c0d
cfd849a945f62d4dc93f01ecaf30011c8a6849d5f6af293dc'
#user1427661: you are seeing the same output as one of the input(say input1) because -
len(input1) > len(input2)
What you possibly can do now is apply a check on the length of the two strings and strip the larger one to match the size of the smaller one (because rest of the part is anyways useless) with something like this-
if len(input1) > len(input2):
input1 = input1[:len(b)]
Likewise an else condition.
Let me give you a more simpler answer (ofcourse in my opinion!). You may use the in-built 'operator' package and then directly use the xor method in it.
http://docs.python.org/2/library/operator.html
Hope this helps.
I need to transmit a value that is larger than 65535 via two different hex strings so that when the strings are received, they can be concatenated to form the integer again. For example if the value was 70000 then the two strings would be 0x0001 and 0x1170.
I thought it would be as simple as converting the integer to hex then shifting it right by 4 to get the top string and removing all but the last 4 characters for the bottom.
I think I might be struggling with some syntax (fairly new to Python) and probably some of the logic too. Can anyone think of an easy way to do this?
Thanks
Use divmod builtin function:
>>> [hex(x) for x in divmod(70000, 65536)]
['0x1', '0x1170']
Your algorithm can be implemented easily, as in Lev Levitsky's answer:
hex(big)[2:-4], hex(big)[-4:]
However, it will fail for numbers under 65536.
You could fix that, but you're probably better off splitting the number, then converting the two halves into hex, instead of splitting the hex string.
ecatmur's answer is probably the simplest way to do this:
[hex(x) for x in divmod(70000, 65536)]
Or you could translate your "shift right/truncate" algorithm on the numbers like this:
hex(x >> 16), hex(x & 0xFFFF)
If you need these to be strings like '0x0006' rather than '0x6', instead of calling hex on the parts, you can do this:
['%#06x' % (x,) for x in divmod(x, 65536)]
Or, using the more modern string formatting style:
['0x{:04x}'.format(x) for x in divmod(x, 65536)]
But on the other side, you again probably want to undo this by converting to ints first and then shifting and masking the numbers, instead of concatenating the strings. The inverse of ecatmur's answer is:
int(bighalf) * 65536 + int(smallhalf)
The (equivalent) inverse of the shift/mask implementation is:
(int(bighalf) << 16) | int(smallhalf)
And in that case, you don't need the extra 0s on the left.
It's also worth pointing out that none of these algorithms will work if the number can be negative, or greater than 4294967295, but only because the problem is impossible in those cases.
You mean like this?
In [1]: big = 12345678
In [2]: first, second = hex(big)[2:][:-4], hex(big)[2:][-4:]
In [3]: first, second
Out[3]: ('bc', '614e')
In [4]: int(first+second, 16)
Out[4]: 12345678
Being wary of big/little endians, what you could do to keep it simple is:
val = 70000
to_send = '{:08X}'.format(val) # '00011170'
decoded = int('00011170', 16) # 70000
EDIT: to be very clear then...
hex1, hex2 = to_send[:4], to_send[4:] # send these two and on receipt
my_number = int(hex1 + hex2, 16)
for numbers greater than 65536 or for numbers whose with length >=5, you can use slicing:
>>> num=70000
>>> var1=hex(num)[:-4]
>>> var2='0x'+hex(num)[-4:]
>>> integ=int(var1+var2[2:],16)
>>> print(integ)
70000