Find the last vowel in a string - python

I cant seem to find the proper way to search a string for the last vowel, and store any unique consonants after that last vowel. I have it set up like this so far.
word = input('Input a word: ')
wordlow = word.lower()
VOWELS = 'aeiou'
last_vowel_index = 0
for i, ch in enumerate(wordlow):
if ch == VOWELS:
last_vowel_index += i
print(wordlow[last_vowel_index + 1:])

I like COLDSPEED's approach, but for completeness, I will suggest a regex based solution:
import re
s = 'sjdhgdfgukgdk'
re.search(r'([^AEIOUaeiou]*)$', s).group(1)
# 'kgdk'
# '[^AEIOUaeiou]' matches a non-vowel (^ being the negation)
# 'X*' matches 0 or more X
# '$' matches the end of the string
# () marks a group, group(1) returns the first such group
See the docs on python regular expression syntax. Further processing is also needed for the uniqueness part ;)

You can reverse your string, and use itertools.takewhile to take everything until the "last" (now the first after reversal) vowel:
from itertools import takewhile
out = ''.join(takewhile(lambda x: x not in set('aeiou'), string[::-1]))[::-1]
print(out)
'ng'
If there are no vowels, the entire string is returned. Another thing to note is that, you should convert your input string to lower case using a str.lower call, otherwise you risk not counting uppercase vowels.
If you want unique consonants only (without any repetition), a further step is needed:
from collections import OrderedDict
out = ''.join(OrderedDict.fromkeys(out).keys())
Here, the OrderedDict lets us keep order while eliminating duplicates, since, the keys must be unique in any dictionary.
Alternatively, if you want consonants that only appear once, use:
from collections import Counter
c = Counter(out)
out = ''.join(x for x in out if c[x] == 1)

You can simply write a function for that:
def func(astr):
vowels = set('aeiouAEIOU')
# Container for all unique not-vowels after the last vowel
unique_notvowels = set()
# iterate over reversed string that way you don't need to reset the index
# every time a vowel is encountered.
for idx, item in enumerate(astr[::-1], 1):
if item in vowels:
# return the vowel, the index of the vowel and the container
return astr[-idx], len(astr)-idx, unique_notvowels
unique_notvowels.add(item)
# In case no vowel is found this will raise an Exception. You might want/need
# a different behavior...
raise ValueError('no vowels found')
For example:
>>> func('asjhdskfdsbfkdes')
('e', 14, {'s'})
>>> func('asjhdskfdsbfkds')
('a', 0, {'b', 'd', 'f', 'h', 'j', 'k', 's'})
It returns the last vowel, the index of the vowel and all unique not-vowels after the last vowel.
In case the vowels should be ordered you need to use an ordered container instead of the set, for example a list (could be much slower) or collections.OrderedDict (more memory expensive but faster than the list).

You can just reverse your string and loop over each letter until you encounter the first vowel:
for i, letter in enumerate(reversed(word)):
if letter in VOWELS:
break
print(word[-i:])

last_vowel will return the last vowel in the word
last_index will give you the last index of this vowel in the input
Python 2.7
input = raw_input('Input a word: ').lower()
last_vowel = [a for a in input if a in "aeiou"][-1]
last_index = input.rfind(last_vowel)
print(last_vowel)
print(last_index)
Python 3.x
input = input('Input a word: ').lower()
last_vowel = [a for a in input if a in "aeiou"][-1]
last_index = input.rfind(last_vowel)
print(last_vowel)
print(last_index)

Related

How to build a list with the duplicated letters from another string - Python - Hangman Game

I'm trying to build a function that when passed a letter and a word as an argument, returns a list of strings with this format: '' for each letter with exception of the given letter. So when passed "house" and "o" should return ["", "o","","","_"] .
The problem is when the letter appears more than one time.
def char_positioner(word, guessAttempt):
listedWordBlanks = list(len(word) * '_')
i = word.index(guessAttempt)
if guessAttempt in word:
listedWordBlanks[i] = word[i]
return listedWordBlanks
This is my second attempt but still getting the same result:
word = ['rotten']
wordSpaces = len(word[0]) * '_'
listWordSpaces = list(wordSpaces)
def testPositioner(char):
for space in listWordSpaces:
if char in word[0]:
for letter in word[0]:
listWordSpaces[word[0].index(char)] = char
return listWordSpaces
testPositioner('t')
Expected result: ['_','_','t','t','_','_',]
**Got:**['_','_','t','_','_','_']
No need to use index. In the end you will have to iterate over all letters, so just go with a simple loop checking each letter if it matches the target letter:
word = "rotten"
res = ['_' for _ in range(len(word))]
target = 't'
for i, letter in enumerate(word):
if letter == target:
res[i] = target
At the end of this, res will be:
['_', '_', 't', 't', '_', '_']
The index() method of string types return the index of the first found element that matches the parameter you pass, a character in your case. That's why it always returns the first letter's index when it's a repeated one. Using your logic, I would modify it as follows:
if char in listWordSpaces:
for index, letter in enumerate(word[0]):
if letter == char:
listWordSpaces[index] = char
As you can see, I used enumerate(), which returns a list of tuples of two elements: the index and the value of each element of the iterable you're iterating over. Then I just compare if the letter in the word is equal to the character and, if so, I put that character in its place in your list.
I would recommend that you not check once against the entire word. Instead check for each position.
def char_positioner(word, guessAttempt):
listedWordBlanks = list(len(word) * '_')
for i, w in enumerate(word):
if w == guessAttempt:
listedWordBlanks[i] = w
return listedWordBlanks
This will ensure that all occurrences of guessAttempt will be captured into listedWordBlanks.

How did I go off-by-one when prepending to a string in a loop?

I am trying to write a program to take a string; find and remove vowel in string, change capital letter to small letter and added "." before each letter. Here's the code:
input_string = "aBAcAba"
vowel = ["a","e","i","o","u"]
list = list(input_string.lower())
for letter in list:
if letter in vowel:
list.remove(letter)
result = ".".join(list)
print (result)
When I run this, I get:
b.c.b
But the desired result is:
.b.c.b
Why isn't . added before the first letter, and how can I fix it?
Instead of removing in place, use a list comprehension to create a new list:
input_string = "aBAcAba"
vowel = {"a","e","i","o","u"}
new_string = ''.join(["."+i.lower() for i in input_string if i.lower() not in vowel])
Output:
'.b.c.b'
Also, changing vowel from a list to a set improves the overall lookup time.
more simply
input_string = "aBAcAba"
vowel = ["a","e","i","o","u"]
list = list(input_string.lower())
for letter in list:
if letter in vowel:
list.remove(letter)
result = "."+".".join(list)
print (result)
result = ".".join(list)
will not add "." before each letter, but will result like you are getting.
if you want "." in starting also you can add extra "."
result="."+".".join(list)
If you just neeed to print it, you can add the '.' on the fly when printing it like this:
print ('', *L, sep=".") # L being the list of remaining non-vowels
This will not create a string though as print() does not return the printed string. The other answers cover how to get the string already. I would still go for a list comprehension to create the partial list:
input_string = "aBAcAba"
vowel = ["a","e","i","o","u"]
L = [c.lower() for c in input_string if c not in vowel]
print ('', *L, sep=".") # *L unpacks it to: print('','b','c','b', sep =".") for your data
The *L will unpack the list, the '' before will add an empty string before it. By declaring a sep="." print will seperate each thing it prints by a '.'
Output:
.b.c.b
inp = 'aBAcAba'
vowels = ['a', 'e', 'i', 'o', 'u']
'.'+'.'.join([c for c in inp.lower() if c not in vowels])
Basically the last line does the trick, it converts input to lower case, check character by character if it's a vowel, finally joins the list to output a string. additional '.' is added at the beginning of the string.
You can also use regular expressions to do that.
Code:
import re
input_string = "aBAcAba"
consonants = re.sub(r'[aeoiu]', '', input_string.lower())
result = f".{'.'.join(consonants)}"
I formatted the result using a Python 3.6+ feature called Literal String Interpolation. I encourage you to find out more about it.
Output:
>>> result
'.b.c.b.'
r'[aeoiuy]' is a pattern that matches one of the vowels within the square brackets.
You can read more about regular expressions here and use this site to test if they match the string.

How to identify a character within a word and substitute that letter into another string - Python

For my hangman project, in the situation that the person does guess a letter correctly, I want to be able to substitute that letter in for a '_' space.
word = input('Please enter a word for your opponent:')
letter = input('Enter a letter to try and guess the word:')
print('_ '*len(word))
if 'a' in word and letter:
print('_ '*len(word) with 'a' in word)
For example if the word entered was 'matt,' the output would be '_a__'
You can use regex substitution with re.sub:
In [514]: word = 'matt'
In [515]: letter = 'a'
In [518]: re.sub(r'[^%s]' %letter, '_', word)
Out[518]: '_a__'
As a tip on how to continue with this approach with subsequent letters, each time the user inputs a letter, add it to letter, like this:
In [521]: new_letter = 't' # replace this with user input
In [522]: letter += new_letter
And, regex will handle the new letter when displaying, appropriately:
In [523]: re.sub(r'[^%s]' %letter, '_', word)
Out[523]: '_att'
You can also do this in a much simpler way.
>>> word_split = list(word)
>>> for a in range(len(word_split)):
... if word_split[a] != letter:
... word_split[a] = "_"
...
>>> print(" ".join(word_split))
_ _ _ _ _ _ _ a _
However #COLDSPEED 's solution is an elegant one.
Here's another non-regex solution. Creates a set of indicies where the given character was found. That is then used to index characters that can be replaced in the list of underscores that's passed in (one approach to update the passed sequence reference in your main game loop).
def subsitute_character(character, target_word, sequence):
indicies = {index for index, element in enumerate(target_word) if element == character}
return ''.join(target_word[index] if index in indicies else element
for index, element in enumerate(sequence))
Sample Output:
>>> s = "matt"
>>> l = ["_" for _ in range(len(s))]
>>> print subsitute_character("t", s, l)
__tt

Python: Find the longest word in a string

I'm preparing for an exam but I'm having difficulties with one past-paper question. Given a string containing a sentence, I want to find the longest word in that sentence and return that word and its length. Edit: I only needed to return the length but I appreciate your answers for the original question! It helps me learn more. Thank you.
For example: string = "Hello I like cookies". My program should then return "Cookies" and the length 7.
Now the thing is that I am not allowed to use any function from the class String for a full score, and for a full score I can only go through the string once. I am not allowed to use string.split() (otherwise there wouldn't be any problem) and the solution shouldn't have too many for and while statements. The strings contains only letters and blanks and words are separated by one single blank.
Any suggestions? I'm lost i.e. I don't have any code.
Thanks.
EDIT: I'm sorry, I misread the exam question. You only have to return the length of the longest word it seems, not the length + the word.
EDIT2: Okay, with your help I think I'm onto something...
def longestword(x):
alist = []
length = 0
for letter in x:
if letter != " ":
length += 1
else:
alist.append(length)
length = 0
return alist
But it returns [5, 1, 4] for "Hello I like cookies" so it misses "cookies". Why? EDIT: Ok, I got it. It's because there's no more " " after the last letter in the sentence and therefore it doesn't append the length. I fixed it so now it returns [5, 1, 4, 7] and then I just take the maximum value.
I suppose using lists but not .split() is okay? It just said that functions from "String" weren't allowed or are lists part of strings?
You can try to use regular expressions:
import re
string = "Hello I like cookies"
word_pattern = "\w+"
regex = re.compile(word_pattern)
words_found = regex.findall(string)
if words_found:
longest_word = max(words_found, key=lambda word: len(word))
print(longest_word)
Finding a max in one pass is easy:
current_max = 0
for v in values:
if v>current_max:
current_max = v
But in your case, you need to find the words. Remember this quote (attribute to J. Zawinski):
Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.
Besides using regular expressions, you can simply check that the word has letters. A first approach is to go through the list and detect start or end of words:
current_word = ''
current_longest = ''
for c in mystring:
if c in string.ascii_letters:
current_word += c
else:
if len(current_word)>len(current_longest):
current_longest = current_word
current_word = ''
else:
if len(current_word)>len(current_longest):
current_longest = current_word
A final way is to split words in a generator and find the max of what it yields (here I used the max function):
def split_words(mystring):
current = []
for c in mystring:
if c in string.ascii_letters:
current.append(c)
else:
if current:
yield ''.join(current)
max(split_words(mystring), key=len)
Just search for groups of non-whitespace characters, then find the maximum by length:
longest = len(max(re.findall(r'\S+',string), key = len))
For python 3. If both the words in the sentence is of the same length, then it will return the word that appears first.
def findMaximum(word):
li=word.split()
li=list(li)
op=[]
for i in li:
op.append(len(i))
l=op.index(max(op))
print (li[l])
findMaximum(input("Enter your word:"))
It's quite simple:
def long_word(s):
n = max(s.split())
return(n)
IN [48]: long_word('a bb ccc dddd')
Out[48]: 'dddd'
found an error in a previous provided solution, he's the correction:
def longestWord(text):
current_word = ''
current_longest = ''
for c in text:
if c in string.ascii_letters:
current_word += c
else:
if len(current_word)>len(current_longest):
current_longest = current_word
current_word = ''
if len(current_word)>len(current_longest):
current_longest = current_word
return current_longest
I can see imagine some different alternatives. Regular expressions can probably do much of the splitting words you need to do. This could be a simple option if you understand regexes.
An alternative is to treat the string as a list, iterate over it keeping track of your index, and looking at each character to see if you're ending a word. Then you just need to keep the longest word (longest index difference) and you should find your answer.
Regular Expressions seems to be your best bet. First use re to split the sentence:
>>> import re
>>> string = "Hello I like cookies"
>>> string = re.findall(r'\S+',string)
\S+ looks for all the non-whitespace characters and puts them in a list:
>>> string
['Hello', 'I', 'like', 'cookies']
Now you can find the length of the list element containing the longest word and then use list comprehension to retrieve the element itself:
>>> maxlen = max(len(word) for word in string)
>>> maxlen
7
>>> [word for word in string if len(word) == maxlen]
['cookies']
This method uses only one for loop, doesn't use any methods in the String class, strictly accesses each character only once. You may have to modify it depending on what characters count as part of a word.
s = "Hello I like cookies"
word = ''
maxLen = 0
maxWord = ''
for c in s+' ':
if c == ' ':
if len(word) > maxLen:
maxWord = word
word = ''
else:
word += c
print "Longest word:", maxWord
print "Length:", len(maxWord)
Given you are not allowed to use string.split() I guess using a regexp to do the exact same thing should be ruled out as well.
I do not want to solve your exercise for you, but here are a few pointers:
Suppose you have a list of numbers and you want to return the highest value. How would you do that? What information do you need to track?
Now, given your string, how would you build a list of all word lengths? What do you need to keep track of?
Now, you only have to intertwine both logics so computed word lengths are compared as you go through the string.
My proposal ...
import re
def longer_word(sentence):
word_list = re.findall("\w+", sentence)
word_list.sort(cmp=lambda a,b: cmp(len(b),len(a)))
longer_word = word_list[0]
print "The longer word is '"+longer_word+"' with a size of", len(longer_word), "characters."
longer_word("Hello I like cookies")
import re
def longest_word(sen):
res = re.findall(r"\w+",sen)
n = max(res,key = lambda x : len(x))
return n
print(longest_word("Hey!! there, How is it going????"))
Output : there
Here I have used regex for the problem. Variable "res" finds all the words in the string and itself stores them in the list after splitting them.
It uses split() to store all the characters in a list and then regex does the work.
findall keyword is used to find all the desired instances in a string. Here \w+ is defined which tells the compiler to look for all the words without any spaces.
Variable "n" finds the longest word from the given string which is now free of any undesired characters.
Variable "n" uses lambda expressions to define the key len() here.
Variable "n" finds the longest word from "res" which has removed all the non-string charcters like %,&,! etc.
>>>#import regular expressions for the problem.**
>>>import re
>>>#initialize a sentence
>>>sen = "fun&!! time zone"
>>>res = re.findall(r"\w+",sen)
>>>#res variable finds all the words and then stores them in a list.
>>>res
Out: ['fun','time','zone']
>>>n = max(res)
Out: zone
>>>#Here we get "zone" instead of "time" because here the compiler
>>>#sees "zone" with the higher value than "time".
>>>#The max() function returns the item with the highest value, or the item with the highest value in an iterable.
>>>n = max(res,key = lambda x:len(x))
>>>n
Out: time
Here we get "time" because lambda expression discards "zone" as it sees the key is for len() in a max() function.
list1 = ['Happy', 'Independence', 'Day', 'Zeal']
listLen = []
for i in list1:
listLen.append(len(i))
print list1[listLen.index(max(listLen))]
Output - Independence

How do I match vowels?

I am having trouble with a small component of a bigger program I am in the works on. Basically I need to have a user input a word and I need to print the index of the first vowel.
word= raw_input("Enter word: ")
vowel= "aeiouAEIOU"
for index in word:
if index == vowel:
print index
However, this isn't working. What's wrong?
Try:
word = raw_input("Enter word: ")
vowels = "aeiouAEIOU"
for index,c in enumerate(word):
if c in vowels:
print index
break
for .. in will iterate over actual characters in a string, not indexes. enumerate will return indexes as well as characters and make referring to both easier.
Just to be different:
import re
def findVowel(s):
match = re.match('([^aeiou]*)', s, flags=re.I)
if match:
index = len(match.group(1))
if index < len(s):
return index
return -1 # not found
The same idea using list comprehension:
word = raw_input("Enter word: ")
res = [i for i,ch in enumerate(word) if ch.lower() in "aeiou"]
print(res[0] if res else None)
index == vowel asks if the letter index is equal to the entire vowel list. What you want to know is if it is contained in the vowel list. See some of the other answers for how in works.
One alternative solution, and arguably a more elegant one, is to use the re library.
import re
word = raw_input('Enter a word:')
try:
print re.search('[aeiou]', word, re.I).start()
except AttributeError:
print 'No vowels found in word'
In essence, the re library implements a regular expression matching engine. re.search() searches for the regular expression specified by the first string in the second one and returns the first match. [aeiou] means "match a or e or i or o or u" and re.I tells re.search() to make the search case-insensitive.
for i in range(len(word)):
if word[i] in vowel:
print i
break
will do what you want.
"for index in word" loops over the characters of word rather than the indices. (You can loop over the indices and characters together using the "enumerate" function; I'll let you look that up for yourself.)

Categories