I'm trying to write a function which will take two hex strings and return their sum in hex value.
Now, I'm not allowed to use "int()" or ".decode" or import any modulo for that matter but make it in the old fashion way of summing each digit (like when we were kids)
the problem is I have no idea how to add two string values as hex values
like if the numbers are "15b" and "ba5" so I want to "put" them like
15b
+
ba5
but now how do I make python know know what is "b"+"5".
any ideas? suggestions?
thx!
Python does know what "b" + "5" is, it's "b5"!
To map those hex characters to integers, you could use a dictionary:
hexmap = {"1": 1, ..., "a": 10, ...}
To work through all the numbers, remember that the indices of the reversed string are powers of 16:
decimal = sum(16**i * hexmap(s) for i, s in enumerate(reversed(hexstring)))
You can then add the two integers together. This is much easier than trying to deal with carrying the extra from adding e.g. b + 9.
Related
I'm doing a little coding in Python, and I came up to the issue that some of my values and not the same length.
Desired length is 15 characters
for example:
string = ['110000111100111', '100100110011011', '001101100110', '01011010001110', '111100111001', '1101100111011']
Some of these values are different, and I want to add zeros to equalise them to the same length. Specifically by adding some zeros to those values that are shorter.
Can someone give me a hand on this?
Many thanks!
I tried comparing them and finding shorter values in the list. I'm new to this.
Try this:
s = ['110000111100111', '100100110011011', '001101100110', '01011010001110', '1100111001', '1101100111011']
s = [x.zfill(15) for x in s]
zfill() will pad a string with zeros on the left, up to the desired string length.
Having list like l1=['abc.123','abc.456','abc.789','abc.153']
I want to sort this list based on numbers which are suffixes. But for that reason I have to convert this string list into integer. How can we do that.
Desired output is : l1= [abc.123,abc.153,abc.456,abc.789]
The safest way is to sort on the integer value of the part after the period, not of the last three characters. This allows for strings with fewer or more digits.
sorted(my_lst, key = lambda x: int(x.split(".")[-1]))
If we know that the last 3 characters are digits we could do:
sorted(my_lst, key = lambda x: int(x[-3:]))
['abc.123', 'abc.153', 'abc.456', 'abc.789']
or even noting that the are 3 numeric characters, you can go ahead and use them:
sorted(my_lst, key = lambda x: x[-3:])
['abc.123', 'abc.153', 'abc.456', 'abc.789']
So I am trying to XOR two strings together but am unsure if I am doing it correctly when the strings are different length.
The method I am using is as follows.
def xor_two_str(a,b):
xored = []
for i in range(max(len(a), len(b))):
xored_value = ord(a[i%len(a)]) ^ ord(b[i%len(b)])
xored.append(hex(xored_value)[2:])
return ''.join(xored)
I get output like so.
abc XOR abc: 000
abc XOR ab: 002
ab XOR abc: 5a
space XOR space: 0
I know something is wrong and I will eventually want to convert the hex value to ascii so am worried the foundation is wrong. Any help would be greatly appreciated.
Your code looks mostly correct (assuming the goal is to reuse the shorter input by cycling back to the beginning), but your output has a minor problem: It's not fixed width per character, so you could get the same output from two pairs characters with a small (< 16) difference as from a single pair of characters with a large difference.
Assuming you're only working with "bytes-like" strings (all inputs have ordinal values below 256), you'll want to pad your hex output to a fixed width of two, with padding zeroes changing:
xored.append(hex(xored_value)[2:])
to:
xored.append('{:02x}'.format(xored_value))
which saves a temporary string (hex + slice makes the longer string then slices off the prefix, when format strings can directly produce the result without the prefix) and zero-pads to a width of two.
There are other improvements possible for more Pythonic/performant code, but that should be enough to make your code produce usable results.
Side-note: When running your original code, xor_two_str('abc', 'ab') and xor_two_str('ab', 'abc') both produced the same output, 002 (Try it online!), which is what you'd expect (since xor-ing is commutative, and you cycle the shorter input, reversing the arguments to any call should produce the same results). Not sure why you think it produced 5a. My fixed code (Try it online!) just makes the outputs 000000, 000002, 000002, and 00; padded properly, but otherwise unchanged from your results.
As far as other improvements to make, manually converting character by character, and manually cycling the shorter input via remainder-and-indexing is a surprisingly costly part of this code, relative to the actual work performed. You can do a few things to reduce this overhead, including:
Convert from str to bytes once, up-front, in bulk (runs in roughly one seventh the time of the fastest character by character conversion)
Determine up front which string is shortest, and use itertools.cycle to extend it as needed, and zip to directly iterate over paired byte values rather than indexing at all
Together, this gets you:
from itertools import cycle
def xor_two_str(a,b):
# Convert to bytes so we iterate by ordinal, determine which is longer
short, long = sorted((a.encode('latin-1'), b.encode('latin-1')), key=len)
xored = []
for x, y in zip(long, cycle(short)):
xored_value = x ^ y
xored.append('{:02x}'.format(xored_value))
return ''.join(xored)
or to make it even more concise/fast, we just make the bytes object without converting to hex (and just for fun, use map+operator.xor to avoid the need for Python level loops entirely, pushing all the work to the C layer in the CPython reference interpreter), then convert to hex str in bulk with the (new in 3.5) bytes.hex method:
from itertools import cycle
from operator import xor
def xor_two_str(a,b):
short, long = sorted((a.encode('latin-1'), b.encode('latin-1')), key=len)
xored = bytes(map(xor, long, cycle(short)))
return xored.hex()
Suppose a string is like this "abaabaabaabaaba", the palindrome cycle here is 3, because you can find the string aba at every 3rd position and you can augment the palindrome by concatenating any number of "aba"s to the string.
I think it's possible to detect this efficiently using Manacher's Algorithm but how?
You can find it easily by searching the string S in S+S. The first index you find is the cycle number you want (may be the entire string). In python it would be something like:
In [1]: s = "abaabaabaabaaba"
In [2]: print (s+s).index(s, 1)
3
The 1 is there to ignore the index 0, that would be a trivial match.
For example, input is a=5678. How do you make b='5678'? (b is a String).
Not allowed to use str2num or any casting.
Is it possible to use log10? (I know how to do the reverse action).
[This is how I did the opposite (from string to num):
s = input('Enter a number: ','s');
x = sum(10.^(length(s-'0')-1:-1:0).*(s-'0'));
This looks like homework, so first here are some hints:
log10 may be useful to determine the number of digits.
mod can help to obtain each digit.
From your code for the reverse action: using successive powers of 10, as well as +'0' / -'0' to convert between digits and ASCII codes, may also be of help here.
And here's a possible approach using these hints (hover the mouse to find out):
b = char(mod(floor(a./10.^((ceil(log10(a))-1):-1:0)),10) + '0'):