Python empty string index error - python

How do I stop the index error that occurs whenever I input an empty string?
s = input("Enter a phrase: ")
if s[0] in ["a","e","i","o","u","A","E","I","O","U"]:
print("an", s)
else:
print("a", s)

You can use the str.startswith() method to test if a string starts with a specific character; the method takes either a single string, or a tuple of strings:
if s.lower().startswith(tuple('aeiou')):
The str.startswith() method doesn't care if s is empty:
>>> s = ''
>>> s.startswith('a')
False
By using str.lower() you can save yourself from having to type out all vowels in both lower and upper case; you can just store vowels into a separate variable to reuse the same tuple everywhere you need it:
vowels = tuple('aeiou')
if s.lower().startswith(vowels):
In that case I'd just include the uppercase characters; you only need to type it out once, after all:
vowels = tuple('aeiouAEIOU')
if s.startswith(vowels):

This will check the boolean value of s first, and only if it's True it will try to get the first character. Since a empty string is boolean False it will never go there unless you have at least a one-character string.
if s and s[0] in ["a","e","i","o","u","A","E","I","O","U"]:
print("an", s)

General solution using try/except:
s = input("Enter a phrase: ")
try:
if s[0].lower() in "aeiou":
print("an", s)
else:
print("a", s)
except IndexError:
# stuff you want to do if string is empty
Another approach:
s = ""
while len(s) == 0:
s = input("Enter a phrase: ")
if s[0].lower() in "aeiou":
print("an", s)
else:
print("a", s)

Even shorter:if s[0:][0] in vowels: but of course this not pass as 'pythonic' I guess. What it does: a slice (variable[from:to]) may be empty without causing an error. We just have to make sure that only the first element is returned in case the input is longer than 1 character.
Edit: no, sorry, this will not work if s=''. You have to use 'if s[0:][0:] in vowels:' but this clearly crosses a line now. Ugly.
Just use
if s:
if s[0] in vowels:
as suggested before.

Related

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)+'!'

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.

Cannot remove two vowels in a row

I have to enter a string, remove all spaces and print the string without vowels. I also have to print a string of all the removed vowels.
I have gotten very close to this goal, but for some reason when I try to remove all the vowels it will not remove two vowels in a row. Why is this? Please give answers for this specific block of code, as solutions have helped me solve the challenge but not my specific problem
# first define our function
def disemvowel(words):
# separate the sentence into separate letters in a list
no_v = list(words.lower().replace(" ", ""))
print no_v
# create an empty list for all vowels
v = []
# assign the number 0 to a
a = 0
for l in no_v:
# if a letter in the list is a vowel:
if l == "a" or l == "e" or l == "i" or l == "o" or l == "u":
# add it to the vowel list
v.append(l)
#print v
# delete it from the original list with a
del no_v[a]
print no_v
# increment a by 1, in order to keep a's position in the list moving
else:
a += 1
# print both lists with all spaces removed, joined together
print "".join(no_v)
print "".join(v)
disemvowel(raw_input(""))
Mistakes
So there are a lot of other, and perhaps better approaches to solve this problem. But as you mentioned I just discuss your failures or what you can do better.
1. Make a list of input word
There are a lot of thins you could do better
no_v = list(words.lower().replace(" ", ""))
You don't replaces all spaces cause of " " -> " " so just use this instead
no_v = list(words.lower().translate( None, string.whitespace))
2. Replace for loop with while loop
Because if you delete an element of the list the for l in no_v: will go to the next position. But because of the deletion you need the same position, to remove all the vowels in no_v and put them in v.
while a < len(no_v):
l = no_v[a]
3. Return the values
Cause it's a function don't print the values just return them. In this case replace the print no_v print v and just return and print them.
return (no_v,v) # returning both lists as tuple
4. Not a mistake but be prepared for python 3.x
Just try to use always print("Have a nice day") instead of print "Have a nice day"
Your Algorithm without the mistakes
Your algorithm now looks like this
import string
def disemvowel(words):
no_v = list(words.lower().translate( None, string.whitespace))
v = []
a = 0
while a < len(no_v):
l = no_v[a]
if l == "a" or l == "e" or l == "i" or l == "o" or l == "u":
v.append(l)
del no_v[a]
else:
a += 1
return ("".join(no_v),"".join(v))
print(disemvowel("Stackoverflow is cool !"))
Output
For the sentence Stackoverflow is cool !\n it outputs
('stckvrflwscl!', 'aoeoioo')
How I would do this in python
Not asked but I give you a solution I would probably use. Cause it has something to do with string replacement, or matching I would just use regex.
def myDisemvowel(words):
words = words.lower().translate( None, string.whitespace)
nv = re.sub("[aeiou]*","", words)
v = re.sub("[^a^e^i^o^u]*","", words)
return (nv, v)
print(myDisemvowel("Stackoverflow is cool !\n"))
I use just a regular expression and for the nv string I just replace all voewls with and empty string. For the vowel string I just replace the group of all non vowels with an empty string. If you write this compact, you could solve this with 2 lines of code (Just returning the replacement)
Output
For the sentence Stackoverflow is cool !\n it outputs
('stckvrflwscl!', 'aoeoioo')
You are modifying no_v while iterating through it. It'd be a lot simpler just to make two new lists, one with vowels and one without.
Another option is to convert it to a while loop:
while a < len(no_v):
l = no_v[a]
This way you have just a single variable tracking your place in no_v instead of the two you currently have.
For educational purposes, this all can be made significantly less cumbersome.
def devowel(input_str, vowels="aeiou"):
filtered_chars = [char for char in input_str
if char.lower() not in vowels and not char.isspace()]
return ''.join(filtered_chars)
assert devowel('big BOOM') == 'bgBM'
To help you learn, do the following:
Define a function that returns True if a particular character has to be removed.
Using that function, loop through the characters of the input string and only leave eligible characters.
In the above, avoid using indexes and len(), instead iterate over characters, as in for char in input_str:.
Learn about list comprehensions.
(Bonus points:) Read about the filter function.

Python 3 - Check letters in string with the next letter

If I have a string
String = 'ABCEEFGH'
How can I check what letter is beside each letter without going out of index?
for index in range(len(String)):
if String[index] == String[index+1]:
print('Double')
You can use enumerate, slicing the string up to the second last character:
String = 'ABCEEFGH'
for ind,ch in enumerate(String[:-1]):
if ch == String[ind+1]:
print('Double')
In your own code the logic would be the same len(String)-1 but enumerate is the way to go:
for index in range(len(String)-1):
if String[index] == String[index+1]:
print('Double')
The fact you seen to only want to check if any two adjacent characters are identical, maybe using any would be best:
String = 'ABCEEFGH'
if any( ch == String[ind+1] for ind, ch in enumerate(String[:-1])):
print('Double',ch)
any will short circuit and break the loop as soon the condition is Trueor else evaluate to False if we have no match.
>>> text = 'ABCEEFGH'
>>> for c1, c2 in zip(text, text[1:]):
if c1 == c2:
print 'double'
double
These kinds of problems are almost always easier if you think of comparing with the previous letter instead of the next one. It's a lot easier to remember letters you've already seen than to look ahead.
text = 'ABCEEFGH'
prev = ''
for letter in text:
if letter == prev:
print("letter duplicated:", letter)
prev = letter
You can use regular expressions:
for match in re.findall(r'([a-z])\1', your_string):
print('Double letters found here.')

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