string index out of range, appears in random lines - python

I tried to make a small program that generates text like this:
M E T A
E E
T T
A A
My code:
line = 0
word = raw_input("")
for i in word:
print i,
print
for i in range(len(word)):
line += 1
print word[line] + " " * (line*2-1) + word[line]
It seems to technically work, but results in
Traceback (most recent call last): File "python", line 11, in IndexError: string index out of range
which can appear in different lines depending on input length. Also, if I input nothing, it will act as if I input RUN instead, but only sometimes. What's the reason behind this weird behaviour? I'm running it within Codeacademy's python lesson, if that makes any difference.

The logical doesn't work either, you need the following:
word = raw_input("Insert a word: ").upper()
print(" ".join(word))
for i in range(1, len(word)):
print(word[i] + " " * (i*2-1) + word[i])

If you already iterating over word chars your line var is useless. It will be enough to do just this:
for i in range(len(word)):
print word[i] + " " * (i*2-1) + word[i]
Or even something like this:
for i, ch in enumerate(word[1:]):
print ch + " " * ((i+1)*2-1) + ch
enumerate here is built-in function to iterate over some collection(word is collection here) and enumerate(index) each element. So on each iteration emumerate returns index of the element i and element itself ch.
word[1:] is operator for taking subset elements from the collection. It means that we will take all values begining from value with index 1.

String indexes go from 0 to len(string)-1. Your variable line has value len(word) in the last iteration, so the expression becomes word[len(word)], which overshoots the index by 1 and results in an "IndexError: string index out of range".

Related

Why is there a memory error showing when I try to run this code?

So I'm having to write a function that does this:
Write the function called remove_all_from_string that takes two strings and returns a copy of
the first string with all instances of the second string removed. You can assume that the
second string is only one letter, like "a". For example remove_all_from_string("house", "h")
would output "ouse" or remove_all_from_string("haus", "h") would output "aus".
It has to have:
A function definition with parameters.
A while loop.
The find method.
Slicing and the + operator.
A return statement.
def remove_all_from_string(word, letter):
while letter in word:
x = word.find(letter)
if x == -1:
continue
else:
new = list(word)
new[x] = ""
word = str(word[:x]) + word.join(new)
return word
print(remove_all_from_string("Mississippi", "i"))
Every time I try to run this, Python displays an Error Message:
Traceback (most recent call last):
File "scratchpad.py", line 22, in <module>
print(remove_all_from_string("Mississippi", "i"))
File "scratchpad.py", line 19, in remove_all_from_string
word = str(word[:x]) + word.join(new)
MemoryError
Could anyone help with this? Thank you for any answers!
Your code getting trapped in a forever loop because of word.join(new) that you are adding word again and again ant word grows to infinity.
The way you can fix your code:
def remove_all_from_string(word, letter):
while letter in word:
x = word.find(letter)
if x == -1:
continue
else:
new = list(word)
new[x] = ""
word = "".join(new[:x] + new[x+1:])
return word
print(remove_all_from_string("Mississippi", "i"))
Better way to implement this function:
def remove_all_from_string(word, letter):
return word.replace(letter, "")
Simplify the while loop's logic:
There's already an answer with the 'best' way to solve the problem. In general, if I think I need a while loop I'm normally wrong, but if they're a requirement they're a requirement I guess.
def remove_all_from_string_converted(word: str, letter: str) -> str:
while letter in word:
index: int = word.find(letter)
word = word[:index] + word[index+1:] # 'join' isn't necessary unless it's also required by a rule
return word
print(remove_all_from_string_converted("Mississippi", "i"))
Output: Msssspp
You are accumulating copies of the variable "word" into itself, which results in exponential growth of the data in the variable, resulting in the computer running out of RAM. Given the task description this is a bug.
As it seems you may be new to programming, I suggest this strategy for helping yourself: print the values of all your variables (and add new variables for important intermediate results) so you can see what your program is actually doing. Once you understand what the program is doing, you can begin to fix it.
def remove_all_from_string(word, letter):
debug_loop_count = 0
while letter in word:
debug_loop_count += 1
if debug_loop_count > 2: # (change this to number control the # of loops you print)
print(f"breaking loop because debug_loop_count exceeded")
break
print(f"--- begin loop iteration #{debug_loop_count}, word: '{word}'")
x = word.find(letter)
if x == -1:
print(f"--- end loop iteration #{debug_loop_count} x={x} (continue)")
continue
else:
new = list(word)
print(f"variable new is: '{new}' x={x}")
new[x] = ""
print(f"variable new is updated to: '{new}' x={x}")
str1 = str(word[:x])
str2 = word.join(new)
print(f"variable str1 is: '{str1}'")
print(f"variable str2 is: '{str2}'")
word = str1 + str2
print(f"variable word now contains: '{word}'")
print(f"--- end iteration loop #{debug_loop_count}")
print(f"!!! end of function, word = {word}")
return word
print(remove_all_from_string("Mississippi", "i"))

String handling in Python

I am trying to write a short python function to break a long one_line string into a multi_line string by inserting \n. the code works fine when i simply insert \n into the string but i get an index out of range error when i insert a conditional check to add hyphenation as well. Here is the code that i have written.
Sentence = "Python string comparison is performed using the characters in both strings. The characters in both strings are compared one by one. When different characters are found then their Unicode value is compared. The character with lower Unicode value is considered to be smaller."
for i in range(1, int(len(Sentence)/40)+1):
x = i*40
Sentence = Sentence[:x] + "\n" if Sentence[x] == " " else "-\n" + Sentence[x:]
print(Sentence)
Here is the error message i get.
Traceback (most recent call last):
File "/media/u1/data/prop.py", line 4, in <module>
Sentence = Sentence[:x] + "\n" if Sentence[x] == " " else "-\n" + Sentence[x:]
IndexError: string index out of range
The conditional expression is greedy, parsed as if you had written
Sentence = Sentence[:x] + \
("\n" if Sentence[x] == " " else "-\n" + Sentence[x:])
As a result, you are doing one of two operations:
Sentence[:x] + '\n' if you find a space
Sentence[:x] + "-\n" + Sentence[x:] if you find a different character.
Note that case 1 shortens your sentence incorrectly, but your range object is based on the original correct list.
The solution is to use parentheses to define the conditional expression correctly:
for i in range(1, int(len(Sentence)/40)+1):
x = i*40
c = Sentence[x]
Sentence = Sentence[:x] + (f"\n" if c == " " else f"{c}-\n") + Sentence[x+1:]
# ^ ^
Well the issue might not be obvious in the start but when you start looking at the if statement in the middle of string concatenation, you will understand. For a minute just focus on the following line:
Sentence = Sentence[:x] + "\n" if Sentence[x] == " " else "-\n" + Sentence[x:]
Python would parse this statement like so:
Sentence = (Sentence[:x] + "\n") if Sentence[x] == " " else ("-\n" + Sentence[x:])
Notice the brackets carefully. This is exactly the reason why the length of the string held by the variable Sentence is decreasing after each iteration which triggers the IndexError exception. Hence, in order to address this issue, we will have to explicitly tell Python what we are expecting. So, it could be written as such:
Sentence = Sentence[:x] + ("\n" if Sentence[x] == " " else "-\n") + Sentence[x:]
string = "Python string comparison is performed using the characters in both strings. The characters in both strings are compared one by one. When different characters are found then their Unicode value is compared. The character with lower Unicode value is considered to be smaller."
stc = ""
for j in range(1 + len(string) // 40):
stc += string[j * 40:40 * (j + 1)] + "\n"
print(stc)

Typecasting a String into an Int within a for loop

How would I store the position variable i as an int so that I can play with that particular position within a string.
sentence = input()
for i in sentence:
if i == " ":
j = int(i) #this line is throwing an error
print (sentence[0:j])
There are two flaws within your code:
if i == " ":
j = int(i)
So you check whether i is a space character, in which case you want to convert that space into a number. Of course that’s not going to work—what number is that space supposed to mean?
The other flaw is the reason why you have a space character there. You say that you want to use the position, or index, of the character. But your for loop does something different than what you expect: for x in sequence will iterate over every element x within that sequence. In case of a string sequence, you will get every character—not an index though.
For example:
>>> for x in 'foo':
print(x)
f
o
o
As you can see, it prints the characters, not the indexes.
You can use enumerate() for this though. Enumerate will enumerate over a sequence giving you the value and the index it appeared at:
>>> for i, x in enumerate('foo'):
print(i, x)
0 f
1 o
2 o
So you get the index too.
In your case, your code would look like this then:
sentence = input()
for i, x in enumerate(sentence):
if x == " ":
print(sentence[0:i])
If You try to find position of ' ' use sentence.index(' '):
sentence = input()
try:
i = sentence.index(' ')
print (sentence[0:j])
except ValueError:
pass
You should use enumerate
for k, v in enumerate(sentence):
if v == " ":
print (sentence[0:k])
You are casting space char to int. Of course does not work.
>>> int(' ')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: ''

What is IndexError? I keep Getting It

Here is my code:
quote = input("Enter a Sentence: ")
a = len(quote)
counter = 0
counter1 = 0
reverse = a
print("The Length of the sentence is",a,"characters long!")
for x in range(0,a):
if str.isspace(quote[x]) == True:
counter = counter + 1
print("The Length of the sentence is",a - counter,"characters long (excluding space...)!")
for x in range(0,a):
if str.isupper(quote[x]) == True:
counter1 = counter1 + 1
print("The number of Upper Case Characters in the sentence is",counter1,"characters!")
print("The number of Lower Case Characters in the sentence is",a-counter1,"characters long!\n")
while reverse >= 1:
r = reverse
print(quote[r])
r = r - 1
It's aim is to find everything about that sentence, but the only problem is the 'While' loop at the bottom. It doesn't seem to work, and it's aim is to 'inverse' the sentence. However, it gives my an error which looks a bit like this:
Traceback (most recent call last):
File "C:\Documents and Settings\ususer\My Documents\Downloads\StringStuff.py", line 27, in <module>
print(quote[r])
IndexError: string index out of range
What Am I doing wrong? Please help!
Python is 0-indexed, so the first character of a string is str[0] and the last is str[len(str) - 1]. So, since you start with reverse = len(quote), at the end you are doing quote[len(quote)], which is one past the end of the string.
So, you should probably start with reverse = a - 1 and your loop at the end should look something like:
while reverse >= 0:
print(quote[reverse])
reverse = reverse - 1
You have run into the common problem that Python starts indexing from 0, but returns the lenght of a list as a valid integer counted from 1. This results that for any list, l[len(l)] will give you IndexError, because a list of length 10 will only have indexes 0...9.
All you have to do is to initialize reverse = len(quote)-1.
You also have to descend your loop variable inside the while loop, so use reverse-=1 instead of r=r-1.

Testing string against a set of vowels - Python

This is a module in my program:
def runVowels():
# explains what this program does
print "This program will count how many vowels and consonants are"
print "in a string."
# get the string to be analyzed from user
stringToCount = input("Please enter a string: ")
# convert string to all lowercase letters
stringToCount.lower()
# sets the index count to it's first number
index = 0
# a set of lowercase vowels each element will be tested against
vowelSet = set(['a','e','i','o','u'])
# sets the vowel count to 0
vowels = 0
# sets the consonant count to 0
consonants = 0
# sets the loop to run as many times as there are characters
# in the string
while index < len(stringToCount):
# if an element in the string is in the vowels
if stringToCount[index] in vowels:
# then add 1 to the vowel count
vowels += 1
index += 1
# otherwise, add 1 to the consonant count
elif stringToCount[index] != vowels:
consonants += 1
index += 1
# any other entry is invalid
else:
print "Your entry should only include letters."
getSelection()
# prints results
print "In your string, there are:"
print " " + str(vowels) + " vowels"
print " " + str(consonants) + " consonants"
# runs the main menu again
getSelection()
However, when I test this program, I get this error:
line 28, in runVowels
stringToCount = input("Please enter a string: ")
File "<string>", line 1
PupEman dABest
^
SyntaxError: unexpected EOF while parsing
I tried adding a + 1 to the "while index < len(stringToCount)" but that didn't help either. I'm pretty new to python and I don't really understand what's wrong with my code. Any help would be appreciated.
I researched this error, all I found out was that EOF stands for end of file. This didn't help at all with resolving my problem. Also, I understand that sometimes the error isn't necessarily where python says the error is, so I double-checked my code and nothing seemed wrong in my eyes. Am I doing this the round-about way by creating a set to test the string elements against? Is there a simpler way to test if string elements are in a set?
Question resolved. Thank you to all!
Looks like you're using Python 2. Use raw_input(...) instead of input(...). The input() function will evaluate what you have typed as a Python expression, which is the reason you've got a SyntaxError.
As suggested use raw_input. Also you don't need to do this:
while index < len(stringToCount):
# if an element in the string is in the vowels
if stringToCount[index] in vowels:
# then add 1 to the vowel count
vowels += 1
index += 1
# otherwise, add 1 to the consonant count
elif stringToCount[index] != vowels:
consonants += 1
index += 1
# any other entry is invalid
else:
print "Your entry should only include letters."
getSelection()
Strings in Python are iterable, so you can just do something like this:
for character in stringToCount:
if character in vowelSet : # Careful with variable names, one is a list and one an integer, same for consonants.
vowels += 1
elif character in consonantsSet: # Need this, if something is not in vowels it could be a number.
consonants += 1
else:
print "Your entry should only include letters."
This should do just fine. Using a while is not necessary here, and very non-Pythonic imho. Use the advantage of using a nice language like Python when you can to make your life easier ;)
You can count the vowels like so:
>>> st='Testing string against a set of vowels - Python'
>>> sum(1 for c in st if c.lower() in 'aeiou')
12
You can do something similar for consonants:
>>> sum(1 for c in st if c.lower() in 'bcdfghjklmnpqrstvwxyz')
26
Also,
if stringToCount[index] in vowels:
should read
if stringToCount[index] in vowelSet:
Here's another way you could solve the same thing:
def count_vowels_consonants(s):
return (sum(1 for c in s if c.lower() in "aeiou"),
sum(1 for c in s if c.lower() in "bcdfghjklmnpqrstvwxyz"))
To wit:
>>> count_vowels_consonants("aeiou aeiou yyy")
(10, 3)
>>> count_vowels_consonants("hello there")
(4, 6)
Python truly is grand.
The errors in your file run as follows (plus some suggestions):
stringToCount = input("Please enter a string: ")
This should be raw_input if you want what the user typed in as a string.
stringToCount.lower()
The .lower() method returns a new string with its letters lowered. It doesn't modify the original:
>>> a = "HELLO"
>>> a.lower()
"hello"
>>> a
"HELLO"
vowelSet = set(['a','e','i','o','u'])
Here you could just as easily do:
vowelSet = set("aeiou")
Note you also don't strictly need a set but it is indeed more efficient in general.
# sets the vowel count to 0
vowels = 0
# sets the consonant count to 0
consonants = 0
Please, you don't need comments for such simple statements.
index = 0
while index < len(stringToCount):
You usually don't need to use a while loop like this in python. Note that all you use index for is to get the corresponding character in stringToCount. Should instead be:
for c in stringToCount:
Now instead of:
if stringToCount[index] in vowels:
vowels += 1
index += 1
You just do:
if c in vowels:
vowels += 1
elif stringToCount[index] != vowels:
consonants += 1
index += 1
# any other entry is invalid
Not quite right. You're checking that a character doesn't equal a set. Maybe you meant:
elif c not in vowels:
consonants += 1
But then there'd be no else case... Got to fix your logic here.
print "In your string, there are:"
print " " + str(vowels) + " vowels"
print " " + str(consonants) + " consonants"
The above is more pythonically written as:
print "In your string, there are: %s vowels %s consonants" % (
vowels, consonants)
# runs the main menu again
getSelection()
Not sure why you're calling that there - why not call getSelection() from whatever calls runVowel()?
Hope that helped! Enjoy learning this great language.
Bah, all that code is so slow ;). Clearly the fastest solution is:
slen = len(StringToCount)
vowels = slen - len(StringToCount.translate(None, 'aeiou'))
consonants = slen - vowels
...note that I don't claim it's the clearest... just the fastest :)

Categories