How do you search for strings within a string? - python

I'm writing a pig latin decoder. This section works with 'qu' works but currently only is the third letter of the word is a vowel. I am implementing an if statement to get it to work for words that have a consonant as the third letter, but keep getting this error: TypeError: 'in ' requires string as left operand, not list
Here is my code:
if w[-2:] == 'ay':
RegW = []
y = w.find('-')
beginningw = w[y:]
if vowel not in beginningw[0]:
RegW.append(beginningw[0:-2] + w[0:y])
else:
RegW.append('qu' + w[0:y])
return RegW[0]
It works for these word:
ay-quay (quay)
iz-quay (quiz)
eue-quay (queue)
but NOT an-quray (quran) (returns quan w/o if statement I'm trying to)

If vowel is a list of vowel characters, I think you want this:
if beginningw[0] not in vowel:

Related

How do I send a character from a string that is NOT a letter or a number to the end of the string?

I am doing a Pig Latin code in which the following words are supposed to return the following responses:
"computer" == "omputercay"
"think" == "inkthay"
"algorithm" == "algorithmway"
"office" == "officeway"
"Computer" == "Omputercay"
"Science!" == "Iencescay!"
However, for the last word, my code does not push the '!' to the end of the string. What is the code that will make this happen?
All of them return the correct word apart from the last which returns "Ience!Scay!"
def pigLatin(word):
vowel = ("a","e","i","o","u")
first_letter = word[0]
if first_letter in vowel:
return word +'way'
else:
l = len(word)
i = 0
while i < l:
i = i + 1
if word[i] in vowel:
x = i
new_word = word[i:] + word[:i] + "ay"
if word[0].isupper():
new_word = new_word.title()
return new_word
For simplicity, how about you check if the word contains an exlamation point ! at the end and if it does just remove it and when you are done add it back. So instead of returning just check place ! at the end (if you discovered it does at the beggining).
def pigLatin(word):
vowel = ("a","e","i","o","u")
first_letter = word[0]
if first_letter in vowel:
return word +'way'
else:
hasExlamation = False
if word[-1] == '!':
word = word[:-1] # removes last letter
hasExlamation = True
l = len(word)
i = 0
while i < l:
i = i + 1
if word[i] in vowel:
x = i
new_word = word[i:] + word[:i] + "ay"
if word[0].isupper():
new_word = new_word.title()
break # do not return just break out of the `while` loop
if hasExlamation:
new_word += "!" # same as new_word = new_word + "!"
return new_word
That way it does not treat ! as a normal letter and the output is Iencescay!. You can of course do this with any other character similarly
specialCharacters = ["!"] # define this outside the function
def pigLatin():
# all of the code above
if word in specialCharacters:
hasSpecialCharacter = True
# then you can continue the same way
Regular expressions to the rescue. A regex pattern with word boundaries will make your life much easier in this case. A word boundary is exactly what it sounds like - it indicates the start- or end of a word, and is represented in the pattern with \b. In your case, the ! would be such a word boundary. The "word" itself consists of any character in the set a-z, A-Z, 0-9 or underscore, and is represented by \w in the pattern. The + means, one or more \w characters.
So, if the pattern is r"\b\w+\b", this will match any word (consisting of any of a-zA-Z0-9_), with leading or succeeding word boundaries.
import re
pattern = r"\b\w+\b"
sentence = "computer think algorithm office Computer Science!"
print(re.findall(pattern, sentence))
Output:
['computer', 'think', 'algorithm', 'office', 'Computer', 'Science']
>>>
Here, we're using re.findall to get a list of all substrings that matched the pattern. Notice, no whitespace or punctuation is included.
Let's introduce re.sub, which takes a pattern to look for, a string to look through, and another string with which to replace any match it finds. Instead of a replacement-string, you can instead pass in a function. This function must take a match object as a parameter, and must return a string with which to replace the current match.
import re
pattern = r"\b\w+\b"
sentence = "computer think algorithm office Computer Science!"
def replace(match):
return "*" * len(match.group())
print(re.sub(pattern, replace, sentence))
Output:
******** ***** ********* ****** ******** *******!
>>>
That's just for demonstration purposes.
Let's change gears for a second:
from string import ascii_letters as alphabet
print(alphabet)
Output:
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
>>>
That's handy for creating a string containing only consonants:
from string import ascii_letters as alphabet
consonants = "".join(set(alphabet) ^ set("aeiouAEIOU"))
print(consonants)
Output:
nptDPbHvsxKNWdYyrTqVQRlBCZShzgGjfkJMLmFXwc
>>>
We've taken the difference between the set of all alpha-characters and the set of only vowels. This yields the set of only consonants. Notice, that the order of the characters it not preserved in a set, but it doesn't matter in our case, since we'll be effectively treating this string as a set - testing for membership (if a character is in this string, it must be a consonant. The order does not matter).
Let's take advantage of this, and modify our pattern from earlier. Let's add two capturing groups - the first will capture any leading consonants (if they exist), the second will capture all remaining alpha characters (consonants or vowels) before the terminating word boundary:
import re
from string import ascii_letters as alphabet
consonants = "".join(set(alphabet) ^ set("aeiouAEIOU"))
pattern = fr"\b([{consonants}]*)(\w+)\b"
word = "computer"
match = re.match(pattern, word)
if match is not None:
print(f"Group one is \"{match.group(1)}\"")
print(f"Group two is \"{match.group(2)}\"")
Output:
Group one is "c"
Group two is "omputer"
>>>
As you can see, the first group captured c, and the second group captured omputer. Separating the match into two groups will be useful later when we construct the pig-latin translation. We can get even cuter by naming our capturing groups. This isn't required, but it will make things a bit easier to read later on:
pattern = fr"\b(?P<prefix>[{consonants}]*)(?P<rest>\w+)\b"
Now, the first capturing group is named prefix, and can be accessed via match.group("prefix"), rather than match.group(1). The second capturing group is named rest, and can be accessed via match.group("rest") instead of match.group(2).
Putting it all together:
import re
from string import ascii_letters as alphabet
consonants = "".join(set(alphabet) ^ set("aeiouAEIOU"))
pattern = fr"\b(?P<prefix>[{consonants}]*)(?P<rest>\w+)\b"
sentence = "computer think algorithm office Computer Science!"
def to_pig_latin(match):
rest = match.group("rest")
prefix = match.group("prefix")
result = rest + prefix
if len(prefix) == 0:
# if the 'prefix' capturing group was empty
# the word must have started with a vowel
# so, the suffix is 'way'
result += "way"
# that also means we need to check if the first character...
# ... (which must be in 'rest') was upper-case.
if rest[0].isupper():
result = result.title()
else:
result += "ay"
if prefix[0].isupper():
result = result.title()
return result
print(re.sub(pattern, to_pig_latin, sentence))
Output:
omputercay inkthay algorithmway officeway Omputercay Iencescay!
>>>
That was the verbose version. The definition of to_pig_latin can be shortened to:
def to_pig_latin(match):
rest = match.group("rest")
prefix = match.group("prefix")
return (str, str.title)[(prefix or rest)[0].isupper()](rest + prefix + "way"[bool(prefix):])

Need help to translate a string to pyg latin

I want to write a function that will take a string and turn the words into Pyg Latin. That means that:
If a word begins with a vowel, add "-way" to the end. Example: "ant" becomes "ant-way".
If a word begins with a consonant cluster, move that cluster to the end and add "ay" to it. Example: "pant" becomes "ant-pay".
I've searched many posts and websites but none of them do the same way or the way I want to do it. I have to test these functions in a test and I have 4 test cases for this one. One is 'fish' and it should returns 'ish-fray' the second is 'frish' and it should returns 'ish-fray' the third is 'ish' and it should return 'ish-way' and the last is 'tis but a scratch' and it should return 'is-tay ut-bay a-way atch-scray'
I've found a program that can translate it CLOSE to what it has to be but I'm not sure how to edit it so it can return the result I'm looking for.
def pyg_latin(fir_str):
pyg = 'ay'
pyg_input = fir_str
if len(pyg_input) > 0 and pyg_input.isalpha():
lwr_input = pyg_input.lower()
lst = lwr_input.split()
latin = []
for item in lst:
frst = item[0]
if frst in 'aeiou':
item = item + pyg
else:
item = item[1:] + frst + pyg
latin.append(item)
return ' '.join(latin)
So, this is the result my code does:
pyg_latin('fish')
#it returns
'ishfay'
What I want it to return isn't much different but I dont know how to add it in
pyg_latin('fish')
#it returns
'ish-fay'
Think about what the string should look like.
Chunk of text, followed by a hyphen, followed by the first letter (if it’s a not a vowel), followed by “ay”.
You can use python string formatting or just add the strings together:
Item[1:] + “-“ + frst + pyg
It is also worth learning how array slicing works and how strings are arrays that can be accessed through the notation. The following code appears to work for your test cases. You should refactor it and understand what each line does. Make the solution more robust but adding test scenarios like '1st' or a sentence with punctuation. You could also build a function that creates the pig latin string and returns it then refactor the code to utilize that.
def pg(w):
w = w.lower()
string = ''
if w[0] not in 'aeiou':
if w[1] not in 'aeiou':
string = w[2:] + "-" + w[:2] + "ay"
return string
else:
string = w[1:] + "-" + w[0] + "ay"
return string
else:
string = w + "-" + "way"
return string
words = ['fish', 'frish', 'ish', 'tis but a scratch']
for word in words:
# Type check the incoming object and raise an error if it is not a list or string
# This allows handling both 'fish' and 'tis but a scratch' but not 5.
if isinstance(word, str):
new_phrase = ''
if ' ' in word:
for w in word.split(' '):
new_phrase += (pg(w)) + ' '
else:
new_phrase = pg(word)
print(new_phrase)
# Raise a Type exception if the object being processed is not a string
else:
raise TypeError

String replace printing too many instances of character 'e'

I am trying to write a function that takes a string as input and returns a string with all vowels repeated 4 times.
eg: apple becomes aaaappleeee
It works for every vowel, except for e, in which it repeats e an egregious amount of times.
Python 3. I have tried playing with the replace function, changing the replacement value to i+i+i+i, i*4, i(4), (i+i)*2, but nothing seems to help.
def exclamation(string):
for i in string:
if i in 'aeiou':
string = string.replace(i, i*4)
return string + '!'
exclamation('excellent') should return eeeexceeeelleeeent!
however, it returns:
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeexceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeelleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeent!
As stated, the function works fine for all other vowels, except e.
Thank you!
You shall never modify something you're iterating over, store the modified word in a new variable. Modifing your code it would be something like
def exclamation(string):
new = ''
for i in string:
if i in 'aeiou':
new += i*4
else:
new += i
return new + '!'
For every vowel you’re iterating through, the loop checks the condition, replaces the content in the same string and then iterates by 1 which now is the same string but instead of the next new letter, it now has to deal with 3 more of the same vowel. For example:
Let’s talk about the string ‘excellent’. For the first vowel ‘e’, it is replaced with ‘eeee’ resulting in the string being ‘eeeexcellent’, now when the second loop begins it starts at index(1) which is still an ‘e’ and this keeps going on. Never modify the iterable you’re iterating over.
It's not that e is being treated differently, but rather that you're replacing each e with eeee for as many es as there are in the word. If you try other words with multiples of the same vowel, you would see the same behavior there.
Instead of replacing for each vowel in the string, you should be doing each replacement once, which will effect every instance of that vowel in the string:
def exclamation(s):
for vowel in 'aeiou':
s = s.replace(vowel, vowel*4)
return s + '!'
print(exclamation('excellent'))
# 'eeeexceeeelleeeent!'
Note that this only works if the word is already lowercase (though that would be easy to fix, add capital vowels to the loop).
Another way of doing this would be to define a translation table to do all of the replacements at once:
trans = str.maketrans({vowel: vowel*4 for vowel in 'aeiou'})
def exclamation(s):
return s.translate(trans)
def exclamation(string):
result = ''
for i in string:
if i in 'aeiou':
vowel = i * 4
else:
vowel = i
result += vowel
return result + '!'
The reason why replace didnt work for excellent is because we have 3 'e' in which means for each of the 'e' in the loop, replace will multiply by 4 which will definitely give you 12 'e's per one 'e' in excellent
It is happening because your loop will consider the replaced 'e's as the element of the string as well.
Here is what I am saying:
String is excellent
Iterate through the string and check if the letter is vowel
If the letter is vowel, write that vowel 4 times.
By following the above steps, we will find this result as the first iteration.
First iteration will work on the first letter which is 'e' and will replace it with 'eeee'. So at the end of the first iteration, our final string will be: 'eeeexcellent'
Now for the second iteration, it will consider the final string we got after the first iteration. And for second iteration, the word to be consider will be 'e' only. So as you can see, you need to maintain the string as it is after each iteration, and save the replaced result to a new string. (it will always be a new string after all as string is not mutable)
def exclamation(string):
tmp = '' #taking temporary variable to store the current data
for i in string:
if i in 'aeiou':
tmp += i*4 # i*4 only if i is vowel
else:
tmp += i # keeping i as it is if it's not vowel
return tmp + '!'
You can also try list list comprehension which is easy to read and understand as well:
def exclamation(string):
newstr = [ i*4 if i in 'aeiou' else i for i in string]
return ''.join(newstr)+'!'

IndexError: string index out of range. Pig Latin

Sorry if I'm being really ignorant, I've started learning to code Python recently (first language) and have been working on this task on codewars.com to create a single word pig latin programme. It is pretty messy, but it seems to work aside from the fact that the message:
Traceback:
in
in pig_latin
IndexError: string index out of range
...comes up. I have looked online and I sort of gather it is likely some piece of code that is just out of line or i need a -1 somewhere or something. I was wondering if anyone could help me identify where this would be. It's not helped of course by the fact that I have made this difficult for myself with my inefficiency :P thanks
def pig_latin(s):
word = 'ay'
word2 = 'way'
total=0
total2=0
lst = []
val = None
#rejecting non character strings
for c in s:
if c.isalpha() == False:
return None
#code for no vowels and also code for all consonant strings
for char in s:
if char in 'aeiou':
total+=1
if total==0:
return s + 'ay'
else:
pass
elif char not in 'aeiou':
total2+=1
if total2 == len(s):
answer_for_cons = s + word
return answer_for_cons.lower()
#first character is a vowel
if s[0] in 'aeiou':
return s + word2
#normal rule
elif s[0] not in 'aeiou':
for c in s:
if c in 'aeiou':
lst.append(s.index(c))
lst.sort()
answer = s[lst[0]:len(s)] + str(s[:lst[0]]) + word
return answer.lower()
The only point where an index is implicated is when you call s[0]. Have you maybe tried running pig_latin with an empty string?
Also, the formatting of your code makes no sense. I am assuming it was lost in the pasting? Everything below val = None should be at least one indent further right.
Now that the indentation is fixed, the code seems to run, but it does raise
IndexError: string index out of range
if we pass pig_latin an empty string. That's because of
if s[0] in 'aeiou':
That will fail if s is the empty string because you can't do s[0] on an empty string. s[0] refers to the first char in the string, but an empty string doesn't have a first char. And of course pig_latin returns None if we pass it a string that contains non-alpha characters.
So before you start doing the other tests, you should check that the string isn't empty, and return something appropriate if it is empty. The simplest way to do that is
if not s:
return ''
I suggest returning s or the empty string if you get passed an invalid string, rather than returning None. A function that returns different types depending on the value of the input is a bit messy to work with.
There are various simplifications and improvements that can be made to your code. For example, there's no need to do elif char not in 'aeiou' after you've already done if char in 'aeiou', since if char in 'aeiou' is false then char not in 'aeiou' must be true. However, we can simply that whole section considerably.
Here's your code with a few other improvements. Rather than using index to find the location of the first vowel we can use enumerate to get both the letter and its index at the same time.
def pig_latin(s):
word = 'ay'
word2 = 'way'
#return empty and strings that contain non-alpha chars unchanged
if not s or not s.isalpha():
return s
#code for no vowels
total = 0
for char in s:
if char in 'aeiou':
total += 1
if total == 0:
return s.lower() + word
#first character is a vowel
if s[0] in 'aeiou':
return s.lower() + word2
#normal rule. This will always return before the end of the loop
# because by this point `s` is guaranteed to contain at least one vowel
for i, char in enumerate(s):
if char in 'aeiou':
answer = s[i:] + s[:i] + word
return answer.lower()
# test
data = 'this is a pig latin test string aeiou bcdf 123'
s = ' '.join([pig_latin(w) for w in data.split()])
print(s)
output
isthay isway away igpay atinlay esttay ingstray aeiouway bcdfay 123

Translation from English to Pig Latin

I'm doing part of the 'PigLatin translation' program.
Here is the part I'm doing writing right now.
input_str = input("Input a word: ")
consonant_check = 0
while input_str[int(consonant_check)] != 'a' or 'e' or 'i' or 'u':
output_str = input_str[:int(consonant_check)] + input_str[0,int(consonant_check)] + 'ay'
consonant_check = int(consonant_check) + 1
else:
print(output_str)
This part is supposed to check if the word input begins with a consonant. If it does, the program could remove all consonants from the beginning of the word and append them to the end of the word. Then append "ay" to the end of the word.
By collecting information online I had some clues about how to make it happen but I think there are still something wrong with my code.
I would approach it similar to what you intended, resulting in the code below.
In short, check the first character of a string. If it's not a vowel (not in ['a','e','i','o','u']), move the character to the end of the string. Keep doing that until you hit a vowel (so 'string' becomes 'trings' then 'ringst' then 'ingstr' before breaking the loop). Once you finally hit a vowel, you leave the loop, and print the modified string + 'ay'. If the first character is a vowel, you leave the loop and print the string + 'ay'.
There's no need to set a consonant check - you're always checking the first character (0). And there's no need to have two variables - just keep modifying and replacing the original string.
word_string = input("Input a word: ")
while word_string[0] not in ['a','e','i','o','u']:
word_string = word_string[1:] + word_string[0:1]
else:
print(word_string + 'ay')
This isn't a direct answer to your question, but my solution to the pig-latin problem. When learning python, I found that looking at completed examples helped a great deal.
word = "snake"
import string
# Create a list of vowels an consonants
vowels = ['a','e','i','o','u','y']
vowels += [v.upper() for v in vowels]
consonants = [x for x in string.ascii_letters if x not in vowels]
if word[0] in consonants:
# Find the first vowel
idx = min([word.find(v) for v in vowels if word.find(v)>0])
# Split the word at this point and add 'ay'
word = word[idx:] + word[:idx] + 'ay'
print(word)
# Returns "akesnay"
I think your logic is overall a little messed up. I would suggest tackling the problem like this.
1.) Check to see if the first letter is a consonant, if not, do nothing, if so, go to step 2
2.) Find all of the consonants in the word and store them in a list
3.) If it is, remove the vowels from the word, and then append all of the consonant onto the end, followed by 'ay'.
There are infinite ways to actually implement this and I think it would be a good exercise for you to try to implement it yourself, but let me know if you need any more help.

Categories