Python : Exiting for loop? - python

I did some research on SO and am aware that many similar questions have been asked but I couldn't quite get my anwser. Anyway, I'm trying to build a library to "encrypt" a string with "Cesar's number" technique wich means I have to take the string and replace each letters with another letter X positions away in the alphabet (I hope that makes sense). Here's my code :
from string import ascii_lowercase, ascii_uppercase
def creer_encodeur_cesar(distance):
retour = lambda x: encodeur_cesar(x, distance)
return retour
def encodeur_cesar(string, distance):
tabLowerCase = list(ascii_lowercase)
tabUpperCase = list(ascii_uppercase)
tabString = list(string)
l_encodedStr = []
for char in tabString:
position = 0
if char == " ":
pass
elif char.isupper():
#do something
elif char.islower():
for ctl in range(0, len(tabLowerCase)):
position = ctl
if char == tabLowerCase[ctl]:
if (ctl + distance) > 26:
position = ctl + distance - 25
char = tabLowerCase[position + distance]
l_encodedStr.append(char)
#How to break out of here??
encodedStr = str(l_encodedStr)
return encodedStr
encodeur5 = creer_encodeur_cesar(5)
print(encodeur5("lionel"))
So, in my second elif statement, I want to break once I have succesfully found and encrypted a character instead of looping trough the whole alphabet. I have tried to use break but it broke out of the main for loop. Not what I want. I saw that I could use try exceptand raise but I don't quite know how I could do that and is it a good idea?
What's the best way to do this? What are the good practices in this case?
Any help would be appreciated and thanks in advance!

You can use the continue keyword.
From the docs:
>>> for num in range(2, 10):
... if num % 2 == 0:
... print "Found an even number", num
... continue
... print "Found a number", num
Found an even number 2
Found a number 3
Found an even number 4
Found a number 5
Found an even number 6
Found a number 7
Found an even number 8
Found a number 9

Related

Issue with Caesar Cipher and while loops

I'm making this Caesar Cipher decoder and I want the program to print every single option (the 26 ways it could be shifted). However, when I run my code nothing shows, what was my error. If you know please tell me, I'm new to coding and in need of help.
import sys
import time
L2I = dict(zip("ABCDEFGHIJKLMNOPQRSTUVWXYZ",range(26)))
I2L = dict(zip(range(26),"ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
msg = ("What is the intercepted message \n")
for character in msg:
sys.stdout.write(character)
sys.stdout.flush()
time.sleep(0.1)
msg_ans = input("> ")
msg_ans = msg_ans.strip()
shift = 0
def decipher(msg_ans,shift):
while shift < 26:
for i in msg_ans.upper():
if i.isalpha() == True :
msg_ans += I2L[ (L2I[i]+ shift)%26 ]
shift += 1
else:
msg_ans += i
shift += 1
print (msg_ans)
decipher(msg_ans,shift)
I expect it to output the 26 ways it can be shifted. However when I put the word 'Hello' I get 'HelloHFNOSMKSTXRQZBGWUCDHBAJLQLKTVAVVFIO' instead of 'IFMMP JGNNQ ...'
There are a couple of issues. First, you're incrementing shift every time you check a single character. In reality, you only want to increment it after each time you cycle completely through the message. You should also move the initialization into the function. There's no reason to pass shift in, since you're just trying all 26 possibilities in order.
def decipher(msg_ans):
shift = 0
while shift < 26:
for i in msg_ans.upper():
if i.isalpha() == True :
msg_ans += I2L[ (L2I[i]+ shift)%26 ]
else:
msg_ans += i
shift += 1
print (msg_ans)
At this point, though, there's no reason to use a while loop instead of a for:
def decipher(msg_ans):
for shift in range(26):
for i in msg_ans.upper():
if i.isalpha() == True :
msg_ans += I2L[ (L2I[i]+ shift)%26 ]
else:
msg_ans += i
print (msg_ans)
The other issue is that you're just appending the new characters to the end of your input string. You don't specify what form you actually want it in, so let's say you want it in a list of strings. You'll need to initialize the list, build a temporary string on each iteration, and then append the temporary string to the list:
def decipher(msg_ans):
possible_messages = []
for shift in range(26):
decoded_msg = ''
for i in msg_ans.upper():
if i.isalpha() == True :
decoded_msg += I2L[ (L2I[i]+ shift)%26 ]
else:
decoded_msg += i
possible_messages.append(decoded_msg)
return possible_messages
Then just print the result of your invocation of the function:
print(decipher(msg_ans))
msg should be like this
msg = "What is the intercepted message \n"
Also you probably want to print instead of return here
return msg_ans

Python: Run-Length Encoding

I'm getting an error if the input only contains a character without a number attached to it. For example, if the user were to input "a2bc" the output should be "aabc". I have to meet the run-length format. The decode function works if its "a2b1c1". The single character doesn't recognize any of it. I played with the conditions and debugger. I can't seem to meet the format for run-length.
The code displayed below were my attempts. I commented on the block where I tried to fix my problems.
def decode(user_input):
if not user_input:
return ""
else:
char = user_input[0]
num = user_input[1]
if num.isdigit():
result = char * int(num)
# elif num.isalpha():
# # this should skip to the next two characters
else:
result = char * int(num)
return result + decode(user_input[2:])
test1 = decode("a2b3c1")
test2 = decode("a2b3c")
print(test1)
print(test2)
(Note: the output for test2 should be "aabbbc")
Thank you so much.
This requires two changes: as you already figured out, if num is not actually a number, then you only use the char once and skip one character ahead. Otherwise you use the number and skip two characters ahead.
But you also need to handle a single character without a number at the end of your string. You can solve this by not only checking if user_input is empty, but whether it only has one character - in both cases you can simply return the string.
def decode(user_input):
if len(user_input) < 2:
return user_input
char = user_input[0]
num = user_input[1]
if num.isdigit():
return char * int(num) + decode(user_input[2:])
else:
return char + decode(user_input[1:])
You should advance by 1 instead of 2 when the next character is not a digit (i.e. the 1 is implicit):
def decode(user_input):
if len(user_input) < 2 : return user_input
multiplier,skip = (int(user_input[1]),2) if user_input[1].isdigit() else (1,1)
return user_input[0] * multiplier + decode(user_input[skip:])
note that doing this recursively will constrain the size of the input string that you can process because of the maximum recursion limit.

Upper case characters every other character but ignoring symbols and spaces

I'm a novice working on a practice script of which I have 90% figured out but am stumped on one portion. I'm doing the mocking spongebob "challenge" on dmoj which asks you to make every other character of a given string upper case, but demands symbols and spaces to be ignored and only letters to be counted.
I and am able to make every other character upper case or lower case, but I am not sure how to ignore symbols and spaces? I'll drop what I have so far for critique. Thank you for your time.
meme1 = "I don't even know her like that"
meme2 = "You can't just make a new meme from a different Spongebob clip every
couple of months"
meme3 = "I must have listened to that latest Ed Sheeran song 10000 times!"
memeFIN1 = [""] * len(meme1)
memeFIN2 = [""] * len(meme2)
memeFIN3 = [""] * len(meme3)
memeFIN1[1::2] = meme1[1::2].upper()
memeFIN2[1::2] = meme2[1::2].upper()
memeFIN3[1::2] = meme3[1::2].upper()
memeFIN1[::2] = meme1[::2].lower()
memeFIN2[::2] = meme2[::2].lower()
memeFIN3[::2] = meme3[::2].lower()
memeFIN1 = "".join(memeFIN1)
memeFIN2 = "".join(memeFIN2)
memeFIN3 = "".join(memeFIN3)
print(memeFIN1)
print(memeFIN2)
print(memeFIN3)
EDIT:
All of the following solutions in the answers helped me come to my own, but none of them seemed to work entirely on their own. In cheesits solution, changing counter to start at 1 works, but not realizing that (as an utter noob) I did counters differently, essentially doing the same thing. This is the solution that worked for me:
meme1 = "I don't even know her like that"
meme2 = "You can't just make a new meme from a different Spongebob clip every couple of months"
meme3 = "I must have listened to that latest Ed Sheeran song 10000 times!"
def spongebobify(meme):
count = 0
char = []
for ch in meme:
if ch.isalpha() and count % 2 == 1:
char.append(ch.upper())
count += 1
elif ch.isalpha():
char.append(ch.lower())
count += 1
else:
char.append(ch)
return ''.join(char)
m1 = spongebobify(meme1)
m2 = spongebobify(meme2)
m3 = spongebobify(meme3)
print (m1)
print (m2)
print (m3)
If you want something readable, try this:
def spongebobify(phrase):
## Turn every character lowercase
phrase = phrase.lower()
## Keep track of how many letters you've seen
counter = 0
## Create a list to hold characters
chars = []
## Go through the entire string
for ch in phrase:
## If this is a letter, increment
if ch.isalpha():
counter += 1
## If this is a letter and our counter is odd:
if ch.isalpha() and counter % 2:
chars.append(ch.upper())
## Otherwise, just add it as-is
else:
chars.append(ch)
return ''.join(chars)
If you want a one liner (disregarding efficiency):
def spongebobify(phrase):
return ''.join([ch.lower() if ch.isalpha() and len([c for c in phrase[:i] if c.isalpha()]) % 2 else ch for i, ch in enumerate(phrase.upper())])
## Readable version:
#return ''.join([
# ch.lower()
# if ch.isalpha()
# and len([c for c in phrase[:i] if c.isalpha()]) % 2
# else ch
# for i, ch in enumerate(phrase.upper())
#])
you can use a bit to indicate which lower/upper you're currently looking at, toggling the bit whenever an alpha character is found.
def speak_like_spongebob(phrase):
case_bit = 0
res = []
for lower_upper in zip(phrase.lower(), phrase.upper()):
res.append(lower_upper[case_bit])
case_bit ^= lower_upper[0].isalpha()
return ''.join(res)
You need to use a loop, so you can increment a counter only when the character is a letter, and then check whether that counter is odd or even.
def mock_spongebob(input):
letters = 0
result = ""
for c in input:
if c.isalpha():
result += c.lower() if letters % 2 == 0 else c.upper()
letters += 1
else:
result += c
return result
As others have mentioned, you will need to iterate through each character in the strings, determine whether it's a character or a symbol, and act accordingly.
The following program would print every other character in uppercase, not counting non-alphabetic characters:
meme1 = "I don't even know her like that"
meme2 = "You can't just make a new meme from a different Spongebob clip every couple of months"
meme3 = "I must have listened to that latest Ed Sheeran song 10000 times!"
for meme in [meme1, meme2, meme3]:
count = 0
meme_mod = ""
for c in meme:
if not c.isalpha():
meme_mod += c
continue
elif count % 2 == 0:
meme_mod += c.lower()
else:
meme_mod += c.upper()
count += 1
print meme_mod
This program would output:
i DoN't EvEn KnOw HeR lIkE tHaT
yOu CaN't JuSt MaKe A nEw MeMe FrOm A dIfFeReNt SpOnGeBoB cLiP eVeRy CoUpLe Of MoNtHs
i MuSt HaVe LiStEnEd To ThAt LaTeSt Ed ShEeRaN sOnG 10000 tImEs!
Here's an article that shows how to write a SpongeBob Mocking Converter script in Python

How to compare Char Strings

So I'm trying to find the least/smallest char in a string. The program is suppose to compare each character to each other and finds the smallest char. Should look like this when calling.
least("rcDefxB")
The least char is B
this is the code that i have so far
def least(inputS):
for i in range(len(inputS)-1):
current = inputS[i]
nextt = inputS[i+1]
if current > nextt:
current = nextt
nextt = inputS[i+2]
print('The least char is',current)
but the output that i get is this:
least("rcDefxB")
C
D
IndexError: string index out of range
in line least nextt = inputS[i+2]
I probably incremented the wrong way or compared my characters the wrong way. I feel like i have the right setup, let me know where i missed up in my code.
You could just use :
min("rcDefxB")
If you really want to write it on your own, you could use :
def leastChar(inputString):
min_char = inputString[0]
for char in inputString:
if char < min_char:
min_char = char
print 'The leastchar is %s' % min_char
Both methods require a non-empty string.
Eric Duminil solution is better, but if you want your code works properly you should modify it as follows:
inputString = "rcDefxB"
index = 0
while index < len(inputString) - 1:
currentChar = inputString[index]
nextChar = inputString[index + 1]
if currentChar > nextChar:
currentChar = nextChar
index += 1
print('The leastchar is',currentChar)
if by smallest you mean the ASCII code position just:
>>> s = "aBCdefg"
>>> min(s)
'B'
but if you mean the alphabet position ignore the upper or lower case:
>>> min(s, key=lambda x: x.upper())
'a'
Please consider the following approach:
def least(inputString):
leastChar = min(list(inputString))
print('The leastchar is', leastChar)
After running least("rcDefxB"), you'll have:
The leastchar is B

Print two appearances of character found in python list

First time here (and a programming noob), hope I get the formatting correct!
I'm trying to make a function that will print out where in a list the occurence of a sought after letter is placed. The code below finds the letter and prints out where in the list the letter is i.e. if you search for 'a' the program will answer it's in the 2nd spot (x+1).
The problem is, if I search for a letter that have more than one occurrencies (for example the letter 'e'), the program finds the letter in both spots but in both cases prints out that it is in the 10th spot.
I'm trying to find out why, should be 10th and 17th in this case.
# store string in variable
solution = list('can you guess me')
guess = raw_input('What letter do you guess on? ')
# Search list
def search(guess):
nothing = 0
for x in solution:
if x == guess:
print x,
print "is in ",
print solution.index(x) + 1
nothing = 1
if nothing == 0:
print "Couldn't find ",
print guess
search(guess)
If choosing e, like this:
What letter do you think is in the answer? e
the program prints out:
e is in 11
e is in 11
I would like to know why. :/
How about this approach:
solution = 'This is the solution'
# Search list
def search(guess):
return [i for i,x in enumerate(solution) if x == guess]
guess = raw_input('Enter your guess: ')
result = search(guess)
if result:
positions = ','.join(str(i+1) for i in result)
print('{0} was found in positions {1}'.format(guess, positions))
else:
print('Sorry, {0} was not found!'.format(guess))
What we are doing here is stepping through the solution and if a character matches the guess, we return its position. If no characters match, then the method will return an empty list; which is a falsey value.
Then, we just check the return value of the method. If it is a list, we add 1 to the position (since list indices start from 0), and then print those out.
solution.index(x) does the same search for you, but will only ever return the first match.
Use enumerate() instead to create an index:
for i, x in enumerate(solution):
if x == guess:
print x,
print "is in ",
print i + 1
nothing = 1
The alternative approach would be to tell solution.index() where to start searching from. The previous position you printed, for example:
last = -1
for x in solution:
if x == guess:
print x,
print "is in ",
last = solution.index(x, last) + 1
print last
nothing = 1

Categories

Resources