I am new to python.
I want to shift char by its position. for e.g.
pos= 3 then replace c by z , b by y , a by x, Same like C by Z , B by Y and A by X
What I have tried ?
I have tried with hardcoded values as,
for i in s:
if ord(i) == 99:
return z
if ord(i) == 98:
return x
...
...
Is there is any builtin function is available to do this ? or Any other simpler way to achieve this ?
Edit:
if string would be "abcdef"
the output would be "xyzabc"
I user input "AbCdEf" then output would be "XyZaBc"
You can use ord combined with chr:
ord("e") + 3
-> 104
chr(ord("e") + 3)
-> 'h'
From your requirements, I understand that you need to demonstrate a Substitution Cipher. It is very simple to implement. I will give you function outline pseudocode:
char substitutionCipher(int leftRotateBy, char alphabet) {
int pos = (int) alphabet - (int) 'a';
pos -= leftRotateBy;
if(pos < 0) {
pos += 26;
}
return (char) (pos + (int) 'a');
}
Please note that this outline will work only for lowercase letters. You can modify it to work for uppercase letters also. Thanks!
If you're using Python 2 and you are wanting to convert entire sentences, consider making a character translation table. https://docs.python.org/2/library/string.html#string.maketrans
import string
def caesar_shift(secret, shift):
lcase = string.ascii_lowercase
ucase = string.ascii_uppercase
shift = shift % len(lcase) # force shift to be between 0 and 25, inclusive
trans = string.maketrans(
''.join([lcase,ucase]),
''.join([lcase[shift:], lcase[shift:],
ucase[shift:], ucase[:shift]]))
return string.translate(secret, trans)
Keep in mind that string.maketrans and string.translate were removed in deprecated in Python 3 as part of improving Python's Unicode string handling.
Use negative or positive values to shift left/right.
https://en.wikipedia.org/wiki/Caesar_cipher
import string
def convert(c, pos):
charset = string.lowercase
index = charset.find(c)
if index >= 0:
return charset[(index - pos) % len(charset)]
charset = string.uppercase
index = charset.find(c)
if index >= 0:
return charset[(index - pos) % len(charset)]
return c
assert convert("c", 3) == "z"
assert convert("b", 3) == "y"
assert convert("a", 3) == "x"
assert convert("C", 3) == "Z"
assert convert("B", 3) == "Y"
assert convert("A", 3) == "X"
Update for those who are interested in better performance:
import string
def get_converter(pos):
def rot(s, pos):
offset = -pos % len(s)
return s[offset:] + s[:offset]
def getzip(charset, pos):
return zip(charset, rot(charset, pos))
def getdict(pos):
return dict(getzip(string.ascii_lowercase, pos) + getzip(string.ascii_uppercase, pos))
chardict = getdict(pos)
def converter(c):
return chardict.get(c, c)
return converter
convert = get_converter(3)
assert convert("c") == "z"
assert convert("b") == "y"
assert convert("a") == "x"
assert convert("C") == "Z"
assert convert("B") == "Y"
assert convert("A") == "X"
assert convert("!") == "!"
Related
So far, I have created the one that returns missing string character. Can we also mix it with integers? For example:
Input: "3629aghrjlsbwofhe"
Output: "014578bcdikmnpqtuvxyz"
Current code for alphabet string:
def missingCharacters(Str):
MAX_CHAR = 26
x = [False for i in range(MAX_CHAR)]
for i in range(len(Str)):
if (Str[i] >= 'a' and Str[i] <= 'z'):
x[ord(Str[i]) - ord('a')] = True
result = ""
for i in range(MAX_CHAR):
if (x[i] == False):
result += chr(i + ord('a'))
return result
You can do the following, using some string utils and a conditional generator expression:
from string import digits, ascii_lowercase
def missingCharacters(s):
# if s is long, this will make the repeated membership test O(1)
# s = set(s)
return "".join(c for c in digits + ascii_lowercase if c not in s)
missingCharacters("3629aghrjlsbwofhe")
# '014578cdikmnpqtuvxyz'
I think this function is for some assignment for your college or company. This could be a naive solution for your problem to show our approach in a clear manner. Just a list update on your code for digits.
def missingCharacters(Str):
MAX_CHAR = 26
x = [False for i in range(MAX_CHAR)]
y = []
for i in range(len(Str)):
if (Str[i] >= 'a' and Str[i] <= 'z'):
x[ord(Str[i]) - ord('a')] = True
if (Str[i].isdigit()):
y.append(int(Str[i]))
result = "".join(str(x) for x in range(10) if x not in y)
for i in range(MAX_CHAR):
if (x[i] == False):
result += chr(i + ord('a'))
return result
I'm trying to learn python.
I got to the point where we're learning loops "for"
and got a bit of a pickle.
1st assignment was to build a function that will count all spaces, my solution was:
def count_spaces(s):
cnt = 0
for char in s:
if char == " ":
cnt = cnt+1
return cnt
and now I'm trying to build a new function, that can accept string, char
and will return the count of the specific char
for example:
print(count_char("Hello world!", " ")
and the screen will show 1 (1 space is found)
this is where i got stuck:
def count_char(s, c):
s=[...]
num = 0
for x in s:
if x == x:
num = s.count(c)
return num
it's returning only 0 ....
please help
You're overwriting your s argument at the start of your function:
s = [...]
which makes the rest impossible to do. Don't do that! :)
If you're allowed to use the count method (like your code is doing) you don't need the for loop at all:
def count_char(s: str, c: str) -> int:
"""The number of character c in string s."""
return s.count(c)
If you wanted to do it without using count, you can write it exactly like your count_space function, but replace the " " with the c parameter:
def count_char(s: str, c: str) -> int:
"""The number of character c in string s."""
cnt = 0
for char in s:
if char == c:
cnt = cnt+1
return cnt
Or you could use a for comprehension along with the sum function:
def count_char(s: str, c: str) -> int:
"""The number of character c in string s."""
return sum(1 if char == c else 0 for char in s)
Or you could use a Counter:
from collections import Counter
def count_char(s: str, c: str) -> int:
"""The number of character c in string s."""
return Counter(s)[c]
I believe instead of
if x == x:
you need
if x == c:
Try this!
def count_spaces(s, c):
cnt = 0
for char in s:
if char == c:
cnt = cnt+1
return cnt
Remove the s=[...]. What ever the ... is, it shouldn't be there because s is an input argument and you do not want to change it.
About the code: It should only be:
count = string.count(substring)
because the str.count() implements what you want to achieve.
If you want to avoid using the built in methods and implement it yourself then you should replace
num = s.count(c) with num += 1 and the x == x (because x will always equal x and you'll be counting all the characters) with x == c like so:
def count_char(s, c):
num = 0
for x in s:
if x == c:
num += 1
return num
Good luck and happy learning!
Remove the s=[...]. What ever the ... is, it shouldn't be there because s is an input argument and you do not want to change it.
About the code: It should only be:
count = string.count(substring)
because the str.count() implements what you want to achieve.
If you want to avoid using the built in methods and implement it yourself then you should replace
num = s.count(c) with num += 1 and the x == x (because x will always equal x and you'll be counting all the characters) with x == c like so:
def count_char(s, c):
num = 0
for x in s:
if x == c:
num += 1
return num
My code for Reverse Integer on LeetCode is not accepted.
I've checked my program could return a correct answer.
class Solution:
def reverse(self, x: int) -> int:
check_num = str(x)
flag = 0
if(check_num[0] == '-'):
check_num = check_num[1:]
flag = 1
elif (check_num[len(check_num)-1] == '0'):
check_num = check_num[:len(check_num)-1]
#print(check_num)
#reverse
time = len(check_num)
storage = [0] * time
for i in range(len(check_num)):
num = len(check_num)-i-1
storage[i] = check_num[num]
#print(storage[i])
if(flag == 1):
storage.insert(0, '-')
#turn to string
oneLinerString=""
for x in storage:
oneLinerString += x
ans = int(oneLinerString)
return oneLinerString
def main():
import sys
import io
def readlines():
for line in io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8'):
yield line.strip('\n')
lines = readlines()
while True:
try:
line = next(lines)
x = int(line);
ret = Solution().reverse(x)
out = str(ret);
print(out)
except StopIteration:
break
if __name__ == '__main__':
main()
For the one input case, my program returns the correct output.
Your input
123
Output
321
Expected
321
But there are errors and my code is not accepted.
What are problems and how should I fix my current code?
Finished in N/A
ValueError: invalid literal for int() with base 10: ''
Line 30 in reverse (Solution.py)
Line 47 in main (Solution.py)
Line 55 in <module> (Solution.py)
For an input of 0, your code will convert the input to an empty string due to:
elif (check_num[len(check_num)-1] == '0'):
check_num = check_num[:len(check_num)-1]
You should remove this elif branch and let your final integer conversion deal with the leading zeros of the reversed number:
ans = int(oneLinerString) # removes leading zeros in the reversed string
You also need to pay attention to the condition regarding returning 0 when the reversed number is outside the range represented in a 32 bit signed integer. Therefore a final check can be added:
if not -2**31 <= ans <= 2**31 - 1:
return 0
Making minimal changes to your sample code, a working solution is:
class Solution:
def reverse(self, x: int) -> int:
check_num = str(x)
flag = 0
if(check_num[0] == '-'):
check_num = check_num[1:]
flag = 1
#print(check_num)
#reverse
time = len(check_num)
storage = [0] * time
for i in range(len(check_num)):
num = len(check_num)-i-1
storage[i] = check_num[num]
#print(storage[i])
if(flag == 1):
storage.insert(0, '-')
#turn to string
oneLinerString=""
for x in storage:
oneLinerString += x
ans = int(oneLinerString) # removes leading zeros in the reversed string
if not -2**31 <= ans <= 2**31 - 1:
return 0
return ans
Try using python to its advantage:
def solve():
n = input()
l = list(map(int,str(n)))
l = l[::-1]
#removing leading zeros
i = 0
while l[i] == 0:
i+=1
l = l[i:]
n = ('').join(str(x) for x in l)
return int(n)
if __name__ == "__main__":
print (solve())
I have converted the int to string and then the string to a list. I can reverse the list easily and then can follow the same procedure to convert the list into an int object again.
num=-1534236469
sign=1
if num<0:
sign=-1
num=num*-1 # make positive for reverse
list1=list(str(num))
list1.reverse()
numrev=int("".join(str(x) for x in list1))*sign
if numrev.bit_length()>31:
numrev=0
The algorithm will take more time compared to the conventional modulus-division method.
I'm trying to find a Python way to diff strings. I know about difflib but I haven't been able to find an inline mode that does something similar to what this JS library does (insertions in green, deletions in red):
one_string = "beep boop"
other_string = "beep boob blah"
Is there a way to achieve this?
One possible way (see also #interjay's comment to the OP) is
import difflib
red = lambda text: f"\033[38;2;255;0;0m{text}\033[38;2;255;255;255m"
green = lambda text: f"\033[38;2;0;255;0m{text}\033[38;2;255;255;255m"
blue = lambda text: f"\033[38;2;0;0;255m{text}\033[38;2;255;255;255m"
white = lambda text: f"\033[38;2;255;255;255m{text}\033[38;2;255;255;255m"
def get_edits_string(old, new):
result = ""
codes = difflib.SequenceMatcher(a=old, b=new).get_opcodes()
for code in codes:
if code[0] == "equal":
result += white(old[code[1]:code[2]])
elif code[0] == "delete":
result += red(old[code[1]:code[2]])
elif code[0] == "insert":
result += green(new[code[3]:code[4]])
elif code[0] == "replace":
result += (red(old[code[1]:code[2]]) + green(new[code[3]:code[4]]))
return result
Which just depends just on difflib, and can be tested with
one_string = "beep boop"
other_string = "beep boob blah"
print(get_edits_string(one_string, other_string))
You can use ndiff.
Example...
import difflib
cases=[('afrykanerskojęzyczny', 'afrykanerskojęzycznym'),
('afrykanerskojęzyczni', 'nieafrykanerskojęzyczni'),
('afrykanerskojęzycznym', 'afrykanerskojęzyczny'),
('nieafrykanerskojęzyczni', 'afrykanerskojęzyczni'),
('nieafrynerskojęzyczni', 'afrykanerskojzyczni'),
('abcdefg','xac')]
for a,b in cases:
print('{} => {}'.format(a,b))
for i,s in enumerate(difflib.ndiff(a, b)):
if s[0]==' ': continue
elif s[0]=='-':
print(u'Delete "{}" from position {}'.format(s[-1],i))
elif s[0]=='+':
print(u'Add "{}" to position {}'.format(s[-1],i))
print()
Returns.....
afrykanerskojęzyczny => afrykanerskojęzycznym
Add "m" to position 20
afrykanerskojęzyczni => nieafrykanerskojęzyczni
Add "n" to position 0
Add "i" to position 1
Add "e" to position 2
afrykanerskojęzycznym => afrykanerskojęzyczny
Delete "m" from position 20
nieafrykanerskojęzyczni => afrykanerskojęzyczni
Delete "n" from position 0
Delete "i" from position 1
Delete "e" from position 2
nieafrynerskojęzyczni => afrykanerskojzyczni
Delete "n" from position 0
Delete "i" from position 1
Delete "e" from position 2
Add "k" to position 7
Add "a" to position 8
Delete "ę" from position 16
abcdefg => xac
Add "x" to position 0
Delete "b" from position 2
Delete "d" from position 4
Delete "e" from position 5
Delete "f" from position 6
Delete "g" from position 7
See this post for more information..
Python - difference between two strings
Try this solution based in Minimum Edit Distance, in this case I use this algorithm to calculate the distance's matrix. After that, the iteration on matrix back to forward to identify what character is included or removed in a string, because this I need invert the result.
To color a terminal I use the colorama module.
#!/bin/python
import sys
from colorama import *
from numpy import zeros
init()
inv_WHITE = Fore.WHITE[::-1]
inv_RED = Fore.RED[::-1]
inv_GREEN = Fore.GREEN[::-1]
def edDistDp(y, x):
res = inv_WHITE
D = zeros((len(x)+1, len(y)+1), dtype=int)
D[0, 1:] = range(1, len(y)+1)
D[1:, 0] = range(1, len(x)+1)
for i in xrange(1, len(x)+1):
for j in xrange(1, len(y)+1):
delt = 1 if x[i-1] != y[j-1] else 0
D[i, j] = min(D[i-1, j-1]+delt, D[i-1, j]+1, D[i, j-1]+1)
#print D
# iterate the matrix's values from back to forward
i = len(x)
j = len(y)
while i > 0 and j > 0:
diagonal = D[i-1, j-1]
upper = D[i, j-1]
left = D[i-1, j]
# check back direction
direction = "\\" if diagonal <= upper and diagonal <= left else "<-" if left < diagonal and left <= upper else "^"
#print "(",i,j,")",diagonal, upper, left, direction
i = i-1 if direction == "<-" or direction == "\\" else i
j = j-1 if direction == "^" or direction == "\\" else j
# Colorize caracters
if (direction == "\\"):
if D[i+1, j+1] == diagonal:
res += x[i] + inv_WHITE
elif D[i+1, j+1] > diagonal:
res += y[j] + inv_RED
res += x[i] + inv_GREEN
else:
res += x[i] + inv_GREEN
res += y[j] + inv_RED
elif (direction == "<-"):
res += x[i] + inv_GREEN
elif (direction == "^"):
res += y[j] + inv_RED
return res[::-1]
one_string = "beep boop"
other_string = "beep boob blah"
print ("'%s'-'%s'='%s'" % (one_string, other_string, edDistDp(one_string, other_string)))
print ("'%s'-'%s'='%s'" % (other_string, one_string, edDistDp(other_string, one_string)))
other_string = "hola nacho"
one_string = "hola naco"
print ("'%s'-'%s'='%s'" % (one_string, other_string, edDistDp(one_string, other_string)))
print ("'%s'-'%s'='%s'" % (other_string, one_string, edDistDp(other_string, one_string)))
what I'm trying to implement is a function that increments a string by one character, for example:
'AAA' + 1 = 'AAB'
'AAZ' + 1 = 'ABA'
'ZZZ' + 1 = 'AAAA'
I've implemented function for the first two cases, however I can't think of any solution for the third case.
Here's my code :
def new_sku(s):
s = s[::-1]
already_added = False
new_sku = str()
for i in s:
if not already_added:
if (i < 'Z'):
already_added = True
new_sku += chr((ord(i)+1)%65%26 + 65)
else:
new_sku += i
return new_sku[::-1]
Any suggestions ?
If you're dealing with bijective numeration, then you probably have (or should have) functions to convert to/from bijective representation anyway; it'll be a lot easier just to convert to an integer, increment it, then convert back:
def from_bijective(s, digits=string.ascii_uppercase):
return sum(len(digits) ** i * (digits.index(c) + 1)
for i, c in enumerate(reversed(s)))
def to_bijective(n, digits=string.ascii_uppercase):
result = []
while n > 0:
n, mod = divmod(n - 1, len(digits))
result += digits[mod]
return ''.join(reversed(result))
def new_sku(s):
return to_bijective(from_bijective(s) + 1)
How about ?
def new_sku(s):
s = s[::-1]
already_added = False
new_sku = str()
for i in s:
if not already_added:
if (i < 'Z'):
already_added = True
new_sku += chr((ord(i)+1)%65%26 + 65)
else:
new_sku += i
if not already_added: # carry still left?
new_sku += 'A'
return new_sku[::-1]
Sample run :-
$ python sku.py Z
AA
$ python sku.py ZZZ
AAAA
$ python sku.py AAA
AAB
$ python sku.py AAZ
ABA
You have to think of 'AAA', 'ZZZ', ... as representation of the value you manipulate.
First, parse the value:
val = sum(pow(26, i) * (ord(v) - ord('A') + 1) for i, v in enumerate(value[::-1]))
Then, add value to it:
val = val + 1
Edit
The final value is given by:
res = ""
while val > 0:
val, n = divmod(val - 1, 26)
res = chr(n+ord('A')) + res
The lack of representation for zero requires the value passed to divmod to be decremented at each turn, which i have not found a way of doing with a list comprehension.
Edit
Rather than ord() and chr(), it is possible to use string.ascii_uppercase.index() and string.ascii_uppercase[]
You can make use of some recursion here:
def new_sku(s):
s = s[::-1]
new_s = ''
return expand(s.upper(), new_s)[::-1]
import string
chars = string.ascii_uppercase
def expand(s, new_s, carry_forward=True):
if not s:
new_s += 'A' if carry_forward else ''
return new_s
new_s += chars[(ord(s[0]) - ord('A') + carry_forward) % 26]
# Slice the first character, and expand rest of the string
if s[0] == 'Z':
return expand(s[1:], new_s, carry_forward)
else:
return expand(s[1:], new_s, False)
print new_sku('AAB')
print new_sku('AAZ')
print new_sku('ZZZ')
print new_sku('aab')
print new_sku('aaz')
print new_sku('zzz')
Output:
AAC
ABA
AAAA
AAC
ABA
AAAA
I would implement this like a base-26 addition with carry.
So start from the right of the string, add 1. If it reaches Z, wrap to A and bump the next left most character up one. If the left most character reaches Z, add an A to the left of the string.
s = ["Z","Z","Z"]
done = 0
index = len(s) - 1
while done == 0:
if s[index] < "Z":
s[index] = chr(ord(s[index]) + 1)
done = 1
else:
s[index] = "A"
if index == 0:
s = ["A"] + s
done = 1
else:
index = index - 1
print s
Just check if the string is all Zs, and if it is, replace it by a string with length len(s) + 1, consisting of just As:
if s == "Z" * len(s):
return "A" * (len(s) + 1)
alp='ABCDEFGHIJKLMNOPQRSTUVWXYZA'
def rec(s):
if len(s)==0:return 'A'
last_letter=s[-1]
if last_letter=='Z':return rec(s[:-1])+'A'
return s[:-1]+alp[(alp.find(last_letter)+1)]
result
>>> rec('AAA')
'AAB'
>>> rec('AAZ')
'ABA'
>>> rec('ZZZ')
'AAAA'
>>> rec('AZA')
'AZB'
How about this? As a simple way to handle the string getting longer you can prepend a leading '#' and strip it if it wasn't incremented:
>>> def new_sku(s):
def increment(s):
if s.endswith('Z'):
return increment(s[:-1])+'A'
else:
return s[:-1]+chr(ord(s[-1])+1)
t = increment('#'+s)
return t.lstrip('#')
>>> new_sku('AAA')
'AAB'
>>> new_sku('AAZ')
'ABA'
>>> new_sku('ZZZ')
'AAAA'
If the recursion worries you then you can flatten it the way you already did but still use the '#' character added and stripped.
You can use a for-else loop:
from string import ascii_uppercase as au
def solve(strs):
lis = []
for i, c in enumerate(strs[::-1], 1):
ind = au.index(c) + 2
lis.append(au[(ind%26)-1])
if ind <= 26:
break
else:
# This will execute only if the for-loop didn't break.
lis.append('A')
return strs[:-1*i] + "".join(lis[::-1])
print solve('AAA')
print solve('AAZ')
print solve('ZZZ')
print solve('AZZZ')
print solve('ZYZZ')
print solve('ZYYZZ')
output:
AAB
ABA
AAAA
BAAA
ZZAA
ZYZAA
We can see there are 3 conditions totally, you can iterate the string and process one of the conditions.
You can use the string.ascii_uppercase instead of chr and ord
import string
def add(s):
s = list(s)[::-1]
for index, char in enumerate(s):
if char != "Z":
s[index] = string.ascii_uppercase[string.ascii_uppercase.index(char) + 1]
return s[::-1]
elif char == "Z" and (index != len(s) - 1):
s[index] = "A"
elif char == "Z" and (index == len(s) - 1):
s[index] = "A"
return ["A"] + s[::-1]