I am new to coding and try to extract and print the none digits. I've written 2 different codes but cannot combine them. I would appreciate some advices. (i tried using *args but didn't work)
def SumOfDigits(str1):
sum_digit = 0
for x in str1:
if x.isdigit():
z = int(x)
sum_digit += z
print("The sum of digits operation is", sum_digit, end=".")
return
def SumOfDigits(input):
valids = []
for character in input:
if character.isalpha():
valids.append(character)
print("The extracted non-digits are:", ''.join(valids))
return
El. Nik, i believe that those 2 function you not be merged as they are doing different behavior, which lead to a more complex function, that might get a bit confusing.
Anyway, what you want is to merge your two for loop into a single one. Since str.isalpha matches do not collide with str.isdigit ones, you can safely use a if statement followed by an elif to check every charater and apply the wanted behavior.
Then, you simply return the 2 results as a tuple.
def digit_extraction(string):
sum_digits = 0
extracted_alphas = ""
for char in string:
if char.isdigit():
sum_digits += int(char)
elif char.isalpha():
extracted_alphas += char
return sum_digits, extracted_alphas
Here is a quick example:
>>> digit_extraction("1a2b3c4d5e6f7g8h9i")
(45, 'abcdefghi')
If you dont know how multiple return value works in python, i'd suggest to check the following tutorial:
https://datagy.io/python-return-multiple-values/
To get into something more advanced, separating the 2 function would allow for writting something considered as more pythonic:
def sum_of_digits(string):
return sum(int(c) for c in string if c.isalpha())
and
def extract_alphas(string):
return ''.join(filter(str.isalpha, c))
Related
I want to convert all the even letters using one function and all the odd numbers using another function. So, each letter represents 0-25 correspsonding with a-z, so a,c,e,g,i,k,m,o,q,s,u,w,y are even characters.
However, only my even letters are converting correctly.
def encrypt(plain):
charCount = 0
answer=[]
for ch in plain:
if charCount%2==0:
answer.append(pycipher.Affine(7,6).encipher(ch))
else:
answer.append(pycipher.Affine(3,0).encipher(ch))
return ''.join(answer)
You never change charCount in your loop -- So it starts at 0 and stays at 0 which means that each ch will be treated as "even".
Based on your update, you actually want to check if the character is odd or even based on it's "index" in the english alphabet. Having some sort of mapping of characters to numbers is helpful here. You could build it yourself:
alphabet = 'abcde...' # string.ascii_lowercase?
mapping = {k: i for i, k in enumerate(alphabet)}
OR we can use the builtin ord noticing that ord('a') produces an odd result, ord('b') is even, etc.
def encrypt(plain):
answer=[]
for ch in plain:
if ord(ch) % 2 == 1: # 'a', 'c', 'e', ...
answer.append(pycipher.Affine(7,6).encipher(ch))
else: # 'b', 'd', 'f', ...
answer.append(pycipher.Affine(3,0).encipher(ch))
return ''.join(answer)
Your basic approach is to re-encrypt a letter each time you see it. With only 26 possible characters to encrypt, it is probably worth pre-encrypting them, then just performing a lookup for each character in the plain text. While doing that, you don't need to compute the position of each character, because you know you are alternating between even and odd the entire time.
import string
def encrypt(plain):
# True == 1, False == 0
fs = [pycipher.Affine(3,0).encipher,
pycipher.Affine(7,6).encipher]
is_even = True # assuming "a" is even; otherwise, just set this to False
d = dict()
for ch in string.ascii_lowercase:
f = fs[is_even]
d[ch] = f(ch)
is_even = not is_even
return ''.join([d[ch] for ch in plain])
You can also use itertools.cycle to simplify the alternation for you.
def encrypt(plain):
# again, assuming a is even. If not, reverse this list
fs = itertools.cycle([pycipher.Affine(3,0).encipher,
pycipher.Affine(7,6).encipher])
d = dict((ch, f(ch)) for f, ch in zip(fs, string.ascii_lowercase))
return ''.join([d[ch] for ch in plain])
This are my two cents on that. What #mgilson is proposing also works of course but not in the way you specified (in the comments). Try to debug your code in your head after writing it.. Go through the for loop and perform 1-2 iterations to see whether the variables take the values you intended them to. charCount is never reassigned a value. It is always 0. And, yes charCount += 1 would make it change but not in the way you want it to..
def encrypt(plain):
alphabet = 'abcdefghijklmnopqrwstuvwxyz'
answer = ''
for letter in plain:
try:
if alphabet.index(letter.lower()) % 2 == 0:
answer += pycipher.Affine(7, 6).encipher(letter)
else:
answer += pycipher.Affine(3, 0).encipher(letter)
except:
answer += letter
return answer
my_text = 'Your question was not very clear OP'
encripted_text = encrypt(my_text)
Also, i would not use ord(ch) because ord('a') = 97 and not 0 therefore odd instead of even.
Since your notion of even letter is based on the position of a character in the alphabet, you could use ord(), like this:
if ord(ch)%2==0:
Note that ord('a') and ord('A') are both odd, so that would make a go in the else part. If you want the opposite, then just negate the condition:
if ord(ch)%2!=0:
So I was messing around in python, and developed a problem.
I start out with a string like the following:
a = "1523467aa252aaa98a892a8198aa818a18238aa82938a"
For every number, you have to add it to a sum variable.Also, with every encounter of a letter, the index iterator must move back 2. My program keeps crashing at isinstance(). This is the code I have so far:
def sum():
a = '93752aaa746a27a1754aa90a93aaaaa238a44a75aa08750912738a8461a8759383aa328a4a4935903a6a55503605350'
z = 0
for i in a:
if isinstance(a[i], int):
z = z + a[i]
elif isinstance(a[i], str):
a = a[:i] + a[(i+1):]
i = i - 2
continue
print z
return z
sum()
This part is not doing what you think:
for i in a:
if isinstance(a[i], int):
Since i is an iterator, there is no need to use a[i], it will confuse Python.
Also, since a is a string, no element of it will be an int, they will all be string. You want something like this:
for i in a:
if i.isdigit():
z += int(i)
EDIT: removing elements of an iterable while iterating over it is a common problem on SO, I would recommend creating a new string with only the elements you wan to keep:
z = 0
b = ''
for i in a:
if i.isdigit():
z += int(i)
b += str(i)
a = b # set a back to b so the "original string" is set to a string with all non-numeric characters removed.
You have a few problems with your code. You don't seem to understand how for... in loops work, but #Will already addressed that problem in his answer. Furthermore, you have a misunderstanding of how isinstance() works. As the numbers are characters of a string, when you iterate over that string each character will also be a (one-length) string. isinstance(a[i], int) will fail for every character regardless of whether or not it can be converted to an int. What you actually want to do is just try converting each character to an int and adding it to the total. If it works, great, and if not just catch the exception and keep on going. You don't need to worry about non-numeric characters because when each one raises a ValueError it will simply be ignored and the next character in the string will be processed.
string = '93752aaa746a27a1754aa90a93aaaaa238a44a75aa08750912738a8461a8759383aa328a4a4935903a6a55503605350'
def sum_(string):
total = 0
for c in string:
try:
total += int(c)
except ValueError:
pass
return total
sum_(string)
Furthermore, this function is equivalent to the following one-liners:
sum(int(c) for c in string if c.isdigit())
Or the functional style...
sum(map(int, filter(str.isdigit, string)))
Recently, I def a function which can compare two words in each wordlist. However, I also found some problems here.
def printcorrectletters():
x=0
for letters in correctanswer:
for letters2 in userinput:
if letters == letters2:
x = x+1
break
return x
In this function, if the correctanswer='HUNTING', and I input 'GHUNTIN', it will show 6 letters are correct. However, I want it compare words' letters 1 by 1. So, it should march 0. For example, 'H' will match first letter of userinput.. and so on.
I also think another function which can solve it by using 'zip'. However, our TA ask me to finish it without things like 'zip'.
If the strings are different lengths, you want to compare each letter of the shorter string:
shortest_length = min(len(correctanswer), len(userinput))
min just gives you the minimum of two or more values. You could code it yourself as:
def min(a, b):
return a if a < b else b
You can index a character in a string, using [index]:
>>> 'Guanfong'[3]
n
So you can loop over all the letter indices:
correct = 0
for index in range(shortest_length):
if correctanswer[index] == userinput[index]:
correct += 1
If you did use zip and sum:
correct = sum(1 for (correct_char, user_char) in zip(correctanswer, userinput)
if correct_char == user_char)
Python provides great facilities for simplifying ideas and for communicating with the computer and programmers (including yourself, tomorrow).
Without zip you can use enumerate() to loop over elements of correctanswer , and get index and element at the same time. Example -
def printcorrectletters():
x=0
for i, letter in enumerate(correctanswer):
if i < len(userinput) and letter == userinput[i]:
x = x+1
return x
Or if even enumerate() is not allowed, simply use range() loop till len(correctanswer) and get elements from each index.
I want to write a function to combine the numbers in the brackets adjacently.
For example, this string as the input
(4)2(2)(2)(2)2(2)
I want the output is
(4)2(6)2(2)
And for example, this string as the input
(2)(2)2(2)(2)(2)24
I want the output is
(4)2(6)24
Currently I wrote a function as follows:
def Combine(i,accumulate,s):
if s[i] == '(':
accumulate += int(s[i+1])
for i in range(i+3,len(s),3):
if s[i] == '(':
accumulate += int(s[i+1])
else:
print s[i-3] + s[i-2] + s[i-1]
i += 3
break
else:
print s[i]
i += 1
Combine(0,0,'(4)2(2)(2)(2)2(2)')
And the output is only:
(4)
I know maybe I need recursive method, but I don't know how to use it correctly.
Can anyone help me?
And I treat it as one-digit problem, and after the sum, I need to convert the number which is more than nine to a corresponding alphabet.
Following is the function:
def toStr(n,base):
convertString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
if n < base:
return convertString[n]
else:
return toStr(n//base,base) + convertString[n%base]
So for example, the input(the base is 17):
(16)
The output needs to be:
(G)
Because I don't know how to modify the function
re.sub(r'((\(\d\))+)', f, '(2)(2)(2)(2)(2)(2)(2)(2)')
Thanks.
I'd use regex for that:
import re
def f(m):
return '({0})'.format(sum(int(x) for x in m.group(1)[1::3]))
re.sub(r'((\(\d\))+)', f, '(4)2(2)(2)(2)2(2)') # (4)2(6)2(2)
The second argument of re.sub can be a function, which you can use to compute the sum:
If repl is a function, it is called for every non-overlapping occurrence
of pattern. The function takes a single match object argument, and
returns the replacement string.
m.group(1) is the matched string, m.group(1)[1::3] is the matched string without parentheses.
sum(int(x) for x in m.group(1)[1::3]) gets us the sum of all digits in the string.
'({0})'.format(sum(int(x) for x in m.group(1)[1::3])) wraps the sum with parentheses (this is the replacement string).
Please note that the code above only works for one-digit numbers. If this is a problem, you'd use
import re
def f(m):
matched = m.group(1).strip('()').split(')(')
return '({0})'.format(sum(int(x) for x in matched))
re.sub(r'((\(\d+\))+)', f, '(42)(2)2') # (44)2
I am trying to find the index of the first letter of a sub string within the main string. The function acts exactly like the find method of python. I have created a find_chr function that gives me the index of a character in a string and I am using the find_chr to get the index of the substring.
def find_str(s,x):
i=0
if x in s:
return find_chr(s,x[i])
else:
return -1
My problem is that when I am using the string "IS GOING GOING" and substring as "ING", I am getting the index of the first "I", when I am expecting the index of the "I" of "ING". I will appreciate any input about changing the function to get the right index of the first letter of the substring.
In find_str you call find_chr(s,x[i]). This is calling find_chr with only x[i] (the ith part of the substring).
This should fix your problem
def find_chr(s,char):
i=0
step = len(char)
for j in range(len(s)+1):
ch = s[j:j+step]
if ch==char:
return (i)
break
i+=1
return -1
def find_str(s,x):
i=0
if x in s:
return find_chr(s,x)
else:
return -1
You aren't looping through the characters, you only check for i == 0 (i.e. the first character in s). You need to apply a "window" to the string, checking len(s) characters in a row:
def find_str(s, x):
if x in s: # is x present?
for i in range(len(s)): # work through string indices
if s[i:i+len(x)] == x: # does x start at current index?
return i
return -1
This should solve your problem:
def find_str(s, x):
i = 0
while i < len(s):
if s[i:i + len(x)] == x:
return i
else:
i += 1
print find_str('IS GOING GOING', 'ING')
Look up the use of the index function in strings. You will then happily replace all of that code with about 1 line.
Supplying the answer because of the following comments. Seriously though, if one is going to learn python, it is a good exercise to be aware of the methods available for an object.
>>> 'is going going'.index('ing')
5
or more generally
>>> fullstring.index(substring)
This should be marked as the correct answer because it is the simplest and most obviously correct. The complexity of the algorithms offered is way too high for this problem.
If the substring is not in the fullstring, a ValueError exception will be raised. So if you need a function, then it should return the index from a try or -1 (or None) from the except blocks.