How do I stop this from exiting after the first iteration? - python

I'm trying to return a statement that replaces given old characters with new characters, but the loop keeps exiting after the first iteration.
def test(s, old_ch, new_ch):
"""returns the given input and replaces an old character with a new character"""
newstring = ""
for ch in s:
while (ch == old_ch):
newstring += new_ch
break
while (ch != old_ch):
newstring += ch
break
return newstring
I know that there are already defined replace functions in python, but this is the way I've been told to do it. (same with the for ch in s bits)

There are two things you need to change.
Instead of using a while-loop and breaking, just use an if-statement. Your code will still work the same way, but it'll be much more readable.
Move the return statement outside of the for-loop, i.e. unindent it. This way newstring won't be returned until the entire for-loop has been executed, which is the desired behavior.
The full corrected code is below:
def test(s, old_ch, new_ch):
"""returns the given input and replaces an old character with a new character"""
newstring = ""
for ch in s:
if (ch == old_ch):
newstring += new_ch
else:
newstring += ch
return newstring
print(test("Megalovania", "a", "o"))
# Prints Megolovonio

for ch in s statement is used to loop over every character of the string.
Hence the while loop inside the for loop is not required.
def test(s, old_ch, new_ch):
"""returns the given input and replaces an old character with a new character"""
newstring = ""
for ch in s:
if(ch == old_ch):
newstring = newstring+new_ch
if(ch != old_ch):
newstring = newstring + ch
return newstring
This code does the intended work you want to achieve.

Try this, so that you will get a better understanding of the iteration.
def test(s, old_ch, new_ch):
newstring = ""
for ch in s:
print(f"ch is {ch}")
if (ch == old_ch):
print(f"if condition is True for ch {ch} and old_ch {old_ch}")
newstring += new_ch
else:
print(f"elif condition is True for ch {ch} and old_ch {old_ch}")
newstring += ch
print(newstring)
return newstring
call this function
test("New to Python", "t", "y")
Output is
ch is N
elif condition is True for ch N and old_ch t
ch is e
elif condition is True for ch e and old_ch t
ch is w
elif condition is True for ch w and old_ch t
ch is
elif condition is True for ch and old_ch t
ch is t
if condition is True for ch t and old_ch t
ch is o
elif condition is True for ch o and old_ch t
ch is
elif condition is True for ch and old_ch t
ch is P
elif condition is True for ch P and old_ch t
ch is y
elif condition is True for ch y and old_ch t
ch is t
if condition is True for ch t and old_ch t
ch is h
elif condition is True for ch h and old_ch t
ch is o
elif condition is True for ch o and old_ch t
ch is n
elif condition is True for ch n and old_ch t

Related

How to check if the parentheses and brackets are balanced?

I need to write a function that given a string with parenthesis and/or square brackets it is able to evaluate if they appear in the correct order. For example, in this string '([b])(aa)' you can see that every time a parenthesis or square bracket is open, it is closed in the correct position. However, a string like '[(a])' it is not closing the parenthesis or square brackets in the correct order as it should be '[(a)]'.
The function should return True or False depending on this correct position of both elements. I have tried the following code, but this logic seems to be infinite and it is not working if I have more than two parenthesis or square brackets opened.
def parenthesis(string):
for a in range(len(string)):
if string[a] == "(":
for b in range(a,len(string)):
if string[b] == "[":
for c in range(b,len(string)):
if string[c] == "]":
for d in range(c,len(string)):
if string[d] == ")":
return True
elif string[b] == ")":
return True
else:
return False
If I run the function over the string "([b])(aa)" it is returning false as output.
parenthesis("([b])(aa)")
How can I rewrite this function so it evaluates all the parenthesis and square brackets combinations properly?
If a right parenthesis is open before a left, you got -1 and return False
def is_balanced(string):
cnt = 0
for char in string:
if char == '(': cnt += 1
if char == ')': cnt -= 1
if cnt < 0: return False
return True if cnt == 0 else False
This is one of the stack implementations I know:
def is_balanced(s):
stack = []
for char in s:
if char == "(" or char == "{" or char == "[":
stack.append(char)
elif len(stack) <= 0:
return False
elif char == ")" and stack.pop() != "(":
return False
elif char == "]" and stack.pop() != "[":
return False
elif char == "}" and stack.pop() != "{":
return False
if len(stack) == 0:
return True
return False
This version is more DRY than the prior answer:
def is_balanced(parens: str) -> bool:
# Link: https://stackoverflow.com/a/73341167/
parens_map ={'(':')','{':'}','[':']'}
stack = []
for paren in parens:
if paren in parens_map: # is open
stack.append(paren)
elif paren in parens_map.values(): # is close
if (not stack) or (paren != parens_map[stack.pop()]):
return False
return not stack

Why my each word reversing code is not reversing some words?

What I want to do
I am trying to make a program that reverses each words, but not reverses words in tags.
Example input and output:
Input:
Thank you stack overflow
Output:
knahT uoy kcats wolfrevo
If the word is in tags, it should be not reversed. Like this:
Input:
<tag>something
Ouput:
<tag>gnihtemos
My code
I tried to solve this using stack algorithm.
s = input()
def stackprint(st):
while st != []:
print(st.pop(), end="")
stack = []
tag = False
for ch in s:
if ch == '<':
stackprint(stack)
tag = True
print(ch, end="")
elif ch == '>':
tag = False
print(ch, end="")
elif tag:
print(ch, end="")
else:
if ch == ' ':
stackprint(stack)
print(ch, end="")
else:
stack.append(ch)
print("".join(stack))
The problem
But, my code is not working if there is only one word or there is no tag. When there is no tag, the last word is not reversed, and when there is only one word, it doesn't get reversed.
The output now:
First
When Input:
<tag>something
Ouput:
<tag>something
^ I need something to be reversed.
Second
Input:
Thank you stack overflow
Ouput:
knahT uoy kcats overflow
^ I need overflow to be reversed.
Important
I need whatever inside < > should be not reversed. If the word is in tags, it should be not reversed
like input:
<tag>word<tag>
output:
<tag>drow<tag>
There will be no space between a tag and a word.
Thank you <tag>stack overflow
knahT uoy <tag>kcats wolfrevo
As I've mentioned in the comment section, instead of printing the stack with the join method, calling the stackprint method to ensure that the stack is emptied will give you the desired result.
s = input()
def stackprint(st):
while st != []:
print(st.pop(), end="")
stack = []
tag = False
for ch in s:
if ch == '<':
stackprint(stack)
tag = True
print(ch, end="")
elif ch == '>':
tag = False
print(ch, end="")
elif tag:
print(ch, end="")
else:
if ch == ' ':
stackprint(stack)
print(ch, end="")
else:
stack.append(ch)
stackprint(stack)
This seems to work with the examples you have provided:
def revSetence(sentence):
sentence = sentence + " ";
flag = False
final_sentence = ""
word = ""
for letter in sentence:
if letter == "<":
flag = True
if letter == ">":
flag = False
if letter.isalpha():
if flag:
final_sentence = final_sentence + letter
else:
word = word + letter
else:
if len(word) > 0:
final_sentence = final_sentence + word[::-1]
final_sentence = final_sentence + letter
word =""
return final_sentence

Looping through a string and only returning certain characters. Python

I have a problem when creating a function that's supposed to first return lowercase letters, "_" and "." and then uppercase letters, " " and "|" in that order. My version seems to return numbers and special characters like <># too which I don't want it to do, It's only supposed to read through the input string once and I don't know if that's achieved with my code.
My code is:
def split_iterative(n):
splitted_first = ""
splitted_second = ""
for i in n:
if i == i.lower() or i == "_" or i == ".":
splitted_first = splitted_first + i
elif i == i.upper() or i == " " or i == "|":
splitted_second = splitted_second + i
return splitted_first + splitted_second
if I do split_iterative("'lMiED)teD5E,_hLAe;Nm,0#Dli&Eg ,#4aI?rN#T§&e7#4E #<(S0A?<)NT8<0'")) it returns "'li)te5,_he;m,0#li&g ,#4a?r#§&e7#4 #<(0?<)8<0'MEDDELANDEINTESANT" which is incorrect as it should eliminate all those special characters and numbers. How do I fix this? It should return ('lite_hemligare', 'MEDDELANDE INTE SANT')
You could try this:
def f(input_string):
str1 = str2 = ""
for character in input_string:
if character.isalpha():
if character.islower():
str1 += character
else:
str2 += character
elif character in "_.":
str1 += character
elif character in " |":
str2 += character
return str1, str2
Output:
>>> input_string = "'lMiED)teD5E,_hLAe;Nm,0#Dli&Eg ,#4aI?rN#T§&e7#4E #<(S0A?<)NT8<0'"
>>>
>>> print f(input_string)
('lite_hemligare', 'MEDDELANDE INTE SANT')
>>>
This is because you are iterating through a string. The lowercase of the special characters is the same as the character. i.e.. '#'.lower() == '#'. hence it'll return '#' and all other special characters. you should explicitly check for alphabets using the isalpha() method on strings.
(i.isalpha() and i.lower() == i) or i == '_' or i == '.'
First, to make it return a list don't return the concatenated string but a list
Second, you are not checking or filtering out the characters, one way would be by checking if the character is a letter using isalpha() method
something like this:
def split_iterative(n):
splitted_first = ""
splitted_second = ""
for i in n:
if (i.isalpha() and i == i.lower()) or i == "_" or i == ".":
splitted_first = splitted_first + i
elif (i.isalpha() and i == i.upper()) or i == " " or i == "|":
splitted_second = splitted_second + i
#returns a list you can make it a variable if you need
return [splitted_first, splitted_second]
You can use ASCII values for the filtering of characters:
def split_iterative(n):
splitted_first = ""
splitted_second = ""
for i in n:
if ord(i) in range(97,122) or i == "_" or i == ".":
splitted_first = splitted_first + i
elif ord(i) in range(65,90) or i == " " or i == "|":
splitted_second = splitted_second + i
return (splitted_first , splitted_second)
You can make use of two lists while walking through characters of your text.
You can append lowercase, underscore, and stop characters to one list then uppercase, space and pipe characters to the other.
Finally return a tuple of each list joined as strings.
def splittext(txt):
slug, uppercase_letters = [], []
slug_symbols = {'_', '.'}
uppercase_symbols = {' ', '|'}
for letter in txt:
if letter.islower() or letter in slug_symbols:
slug.append(letter)
if letter.isupper() or letter in uppercase_symbols:
uppercase_letters.append(letter)
return ''.join(slug), ''.join(uppercase_letters)
txt="'lMiED)teD5E,_hLAe;Nm,0#Dli&Eg ,#4aI?rN#T§&e7#4E #<(S0A?<)NT8<0'"
assert splittext(txt) == ("lite_hemligare", "MEDDELANDE INTE SANT")

Why does this code not print the characters backwards

def anti_vowel(text):
p=''
for c in text:
if c=='a' or c=='A':
break
elif c=='e' or c=='E':
break
elif c=='i' or c=='I':
break
elif c=='o' or c=='O':
break
elif c=='u' or c=='U':
break
else:
p=p+c
print(anti_vowel('Hello you'))
You forgot to return p at the end of your function:
def anti_vowel(text):
p=''
for c in text:
if c=='a' or c=='A':
break
elif c=='e' or c=='E':
break
elif c=='i' or c=='I':
break
elif c=='o' or c=='O':
break
elif c=='u' or c=='U':
break
else:
p=p+c
return p
Without that last line all you'll ever print is None, the default return value for functions without an explicit return statement.
Of course, your function will only ever print the first consonants, as break ends the loop as soon as you find any vowels. It'll not reverse the string, ever. For your sample input, the function return 'H', because the next letter in the input is a vowel, and break then ends the loop.
You could easily re-write your function to use str.lower() and a containment test:
def anti_vowel(text):
p = ''
for c in text:
if c.lower() in 'aeiou':
break
p += c
return p
This does the same thing, return the first consonants ('H' for your sample input).
If you wanted to reverse letters, and exclude vowels, don't use break and invert where you place the remaining letters. You could use continue instead, or more simply, just invert the if test and only process a chararter if it is not a vowel:
def anti_vowel(text):
p = ''
for c in text:
if c.lower() not in 'aeiou':
p = c + p
return p
Now consonants are placed before any preceding consonants, reversing the text:
>>> def anti_vowel(text):
... p = ''
... for c in text:
... if c.lower() not in 'aeiou':
... p = c + p
... return p
...
>>> anti_vowel('Hello you')
'y llH'

Translating sentences into pig latin

SO i have this assignment to translate multiple words into pig latin. assume that the user will always input lowercase and only letters and spaces.
#----------------global variables
sentence = input("What do you want to translate into piglattin? ")
sentence = list(sentence)
sentence.insert(0, ' ')
length = len(sentence)
sentence.append(' ')
pigLattin = sentence
false = 0
true = 1
consonant = []
a = 0
b = 0
c = 0
d = 0
e = 0
f = 0
j = 0
x = 0
y = 0
#----------------main functions
def testSpace(sentence, i):
if sentence[i] == ' ':
a = true
else:
a = false
return a
def testVowel(sentence, i):
if sentence[i] == 'a' or sentence[i] == 'e' or sentence[i] == 'i' or sentence[i] == 'o' or sentence[i] == 'u' or sentence[i] == 'y':
b = true
else:
b = false
return b
def testStartWord(sentence, i):
x = 0
if sentence[i].isalpha() and sentence[i-1] == ' ':
c = true
x = 1
if x == 1 and sentence[i] != 'a' and sentence[i] != 'e' and sentence[i] != 'i' and sentence[i] != 'o' and sentence[i] != 'u' and sentence[i] != 'y':
c = true
else:
c = false
return c
def testWordEnd(sentence, i):
if sentence[i].isalpha() and sentence[i+1] == ' ':
d = true
else:
d = false
return d
#----------------main loop
for i in range(1,length):
x = 0
space = testSpace(sentence, i)
vowel = testVowel(sentence, i)
word = testStartWord(sentence, i)
end = testWordEnd(sentence, i)
if vowel == false and space == false and word == true:
e = i
consonant.append(sentence[i])
pigLattin.pop(e)
f = f + 1
if end == true:
consonant.append('a')
consonant.append('y')
consLength = len(consonant)
for x in range(consLength):
y = i + j - f
pigLattin.insert(y,consonant[x])
j = j + 1
del consonant[:]
pigLength = len(pigLattin)
for b in range (pigLength):
print(pigLattin[b], end='')
this is what i have so far. it gets kinda messy when trying to remove items. im sort of stuck here and its not working.
OK i got it working now this is an updated version
sentence = input("Please enter a sentence: ")
vowels = ("a", "e", "i", "o", "u", "A", "E", "I", "O", "U")
words = sentence.split()
count = 0
def find_vowel(word):
for i in range(len(word)):
if word[i] in vowels:
return i
return -1
for word in words:
vowel = find_vowel(word)
if(vowel == -1):
print(word, ' ', end='')
elif(vowel == 0):
print(word + "ay", ' ', end='')
else:
print(word[vowel:] + word[:vowel] + "ay", ' ', end='')
Instead of using testSpace eliminate the spaces by using sentence = sentence.split(). This will split all your words into strings in a list. Then iterate through the words in your list.
Instead of using testStartWord, use an if statement:
for word in sentence:
if word[0] in ["a","e","i","o","u"]:
word[:(len(word)-1)] = word[0]
#More Code...
At the end, where you print the output, use print sentence.join()
Here's an alternate version. I use a regular expression to find words in the input string, pass them to a callback function, and substitute them back into the original string. This allows me to preserve numbers, spacing and punctuation:
import re
import sys
# Python 2/3 compatibility shim
inp = input if sys.hexversion >= 0x3000000 else raw_input
VOWELS = set('aeiouyAEIOUY')
YS = set('yY')
def pig_word(word):
"""
Given a word, convert it to Pig Latin
"""
if hasattr(word, 'group'):
# pull the text out of a regex match object
word = word.group()
# find the first vowel and what it is
vowel, where = None, None
for i,ch in enumerate(word):
if ch in VOWELS:
vowel, where = ch, i
break
if vowel is None:
# No vowels found
return word
elif where == 0 and vowel not in YS:
# Starts with a vowel - end in 'way'
# (leading y is treated as a consonant)
return word + 'way'
else:
# Starts with consonants - move to end and follow with 'ay'
# check capitalization
uppercase = word.isupper() and len(word) > 1
titlecase = word[:1].isupper() and not uppercase
# rearrange word
word = word[where:] + word[:where] + 'ay'
# repair capitalization
if uppercase:
word = word.upper()
elif titlecase:
# don't use str.title() because it screws up words with apostrophes
word = word[:1].upper() + word[1:].lower()
return word
def pig_latin(s, reg=re.compile('[a-z\']+', re.IGNORECASE)):
"""
Translate a sentence into Pig Latin
"""
# find each word in the sentence, pass it to pig_word, and insert the result back into the string
return reg.sub(pig_word, s)
def main():
while True:
s = inp('Enter a sentence to translate (or Enter to quit): ')
if s.strip():
print(pig_latin(s))
print('')
else:
break
if __name__=="__main__":
main()
then
Enter a sentence to translate (or Enter to quit):
>>> Hey, this is really COOL! Let's try it 3 or 4 times...
Eyhay, isthay isway eallyray OOLCAY! Et'slay ytray itway 3 orway 4 imestay...

Categories