Index out of range for string of length 1 - python

I am practicing recursive function for reversing a string.
Whenever there is no space between quotation marks in str1 == '', the code works fine.
However, if I do put a space in between the quotes in str1 == ' ', I get an error: String index out of range. (since both indices -1 and 0 are valid for str1 with space in quotes)
I do not understand why this error occurs and how to eliminate it.
def reverse(str1):
if str1 ==''
return str1
else:
return str1[-1]+reverse[:-1]
def main():
str1 = input ('Enter string')
result = reverse(str1)
print ('Reverse of string is ', result)
if __name__=='__main__':
main()

You could change reverse function like this:
return str1[::-1]
This will reverse irrespective of the length of string. Hope this works.

chars = [char for char in str1]
chars.reverse()
print(''.join(chars))

As Sam Stafford said in another answer and the comment from gilch, changing the base case and recursively calling the function on the string without the last character will allow the function to work. Something like:
def reverse(str1):
if len(str1) == 1:
return str1
else:
return str1[-1] + reverse(str1[:-1])

First: a semicolon is ;, a quotation mark is '. :)
The strings '' and ' ' are not the same -- one is an empty string, the other is a string that is one character long.
Your recursive function works by slicing the string into smaller and smaller pieces. Once it reaches an empty string, it needs to return instead of slicing it any further. This is called a "base case" -- a special check for the case that you can't solve by recursing further.
When you change your "base case" check so that it no longer catches the empty string (''), it breaks the function, because it will then continue on to attempt to slice, and that raises the exception you're seeing. The value of str1 that causes your function to break is '' (no space), and your recursion will always end in that value, so making this change to your code will always break it.

Related

Can't wrap my head around how to remove a list of characters from another list

I've been able to isolate the list (or string) of characters I want excluded from a user entered string. But I don't see how to then remove all these unwanted characters. After I do this, I think I can try joining the user string so it all becomes one alphabet input like the instructions say.
Instructions:
Remove all non-alpha characters
Write a program that removes all non-alpha characters from the given input.
For example, if the input is:
-Hello, 1 world$!
the output should be:
Helloworld
My code:
userEntered = input()
makeList = userEntered.split()
def split(userEntered):
return list(userEntered)
if userEntered.isalnum() == False:
for i in userEntered:
if i.isalpha() == False:
#answer = userEntered[slice(userEntered.index(i))]
reference = split(userEntered)
excludeThis = i
print(excludeThis)
When I print excludeThis, I get this as my output:
-
,
1
$
!
So I think I might be on the right track. I need to figure it out how to get these characters out of the user input. Any help is appreciated.
Loop over the input string. If the character is alphabetic, add it to the result string.
userEntered = input()
result = ''
for char in userEntered:
if char.isalpha():
result += char
print(result)
This can also be done with a regular expression:
import re
userEntered = input()
result = re.sub(r'[^a-z]', '', userEntered, flags=re.I)
The regexp [^a-z] matches anything except an alphabetic character. The re.I flag makes it case-insensitive. These are all replaced with an empty string, which removes them.
There's basically two main parts to this: distinguish alpha from non-alpha, and get a string with only the former. If isalpha() is satisfactory for the former, then that leaves the latter. My understanding is that the solution that is considered most Pythonic would be to join a comprehension. This would like this:
''.join(char for char in userEntered if char.isalpha())
BTW, there are several places in the code where you are making it more complicated than it needs to be. In Python, you can iterate over strings, so there's no need to convert userEntered to a list. isalnum() checks whether the string is all alphanumeric, so it's rather irrelevant (alphanumeric includes digits). You shouldn't ever compare a boolean to True or False, just use the boolean. So, for instance, if i.isalpha() == False: can be simplified to just if not i.isalpha():.

Trying to replace text but the string is unchanged

Write a Python program to get a string from a given string where all occurrences of its first char have been changed to '$', except the first char itself
My code goes like this:
stringa = "restart"
def swaping(palavra):
prim = palavra[0]
for i in palavra:
if prim in palavra and prim not in palavra[0]:
palavra.replace(prim, "$")
return palavra
print(swaping(stringa))
It should have returned resta$t, but it returned the same form, restart.
Does anyone have an idea why it won't work? The sample solution is completely different from mine, they chose to split the string in two and bind them together in the end.
The reason why your string stayed the same is because the if statement always returns False:
prim in palavra is always True because prim is the first character in the string palavra.
prim not in palavra[0] is always False because prim is palavra[0], thus it is always in itself.
Combining them with an and clause and you'll get a False every time.
Also, str.replace will replace every occurence it finds (most of the times). There's no way to replace a character at a particular index in Python but to slice that string in half and do what your solution does.
Regardless, there's a simpler solution using str.replace:
def swapping(string):
return string[0] + string[1:].replace(string[0], '$')
Just a simple replace(), like this:
string = 'restart'
new_str = string.replace('r', '$').replace('$', 'r', 1)
new_str
Output:
'resta$t'
In your code as I can see it never be go into the if loop because prim not in palavra[0] gives always False as we assign prim = palavra[0], so your 'string' is not changed.
I suggest to use below code:
stringa = "restart"
def swaping(palavra):
prim = palavra[0]
palavra = ''.join([prim,palavra[1:].replace(prim,'$')])
return palavra
print(swaping(stringa))
you need to iterate through the string and match the occurrence of the first character with each element if matched then add $ in the resultant string else add the same character in the resultant string and return that resultant string
def func(string):
if len(string)<2:
return string
first = string[0]
result = first
for i, v in enumerate(string[1:]):
if v==first:
result+='$'
else:
result+=v
return result
result = func('restart')
print(result)
output
resta$t

Check that input is composed of letters from other word

I have this code:
print('abcdefg')
input('Arrange word from following letters: ')
I want to return True if the input consists of letters from the printed string but it doesn't have to have all of printed letters.
That's a perfect use case for sets especially for set.issubset:
print('abcdefg')
given_input = input('Arrange word from following letters: ')
if set(given_input).issubset('abcdefg'):
print('True')
else:
print('False')
or directly print (or return) the result of the issubset operation without if and else:
print(set(given_input).issubset('abcdefg'))
This sounds a little like homework...
Basically you would need to do this: Store both strings in variables. e.g. valid_chars and s.
Then loop through s one character at a time. For each character check if it is in valid_chars (using the in operator). If any character is not found in valid_chars then you should return False. If you get to the end of the loop, return True.
If the valid_chars string is very long it would be better to first put them into a set but for short strings this is not necessary.

Making Parentheses Even?

I'm trying to write a program that asks the user for a string input without using global variables. If the string has parentheses only side by side, then it's even. if it has letters, numbers, or the parentheses are spaced out, then it's uneven. For example, () and ()() is even, whereas (() and (pie) is not. Below is what I've written so far. Do I have to create more than one function for this problem?
def recursion():
string = str(input("Enter your string: "))
if string == "(" or ")":
print("The string is even.")
else:
print("The string is not even.")
A really useful stdlib script shlex provides this type of parsing automatically and allows you to customize the behavior.
No, you do not need to make multiple functions for this. In fact, I would personally just do this:
def recursion():
print("The string is not even." if input("Enter your string: ").replace('()','') else "The string is even.")
There really isn't a need to have a 6 line function for this job. Instead, use a ternary statement like I did to keep it concise.
Also, just wanted to mention this, there is no need to do:
str(input())
because input always returns a string in Python 3.x.
I will collect much of the information in the comments into an answer.
First, in your posted code the line
if string == "(" or ")":
will always evaluate to True because a non-empty string is always True. What you have written is equivalent to:
if ( string == "(" ) or ")":
which is therefore equivalent to
if ( string == "(" ) or True:
which is always True.
Next, since it seems that you simply want to check if your string consists only of sets of '()', you can use Jon Clements' suggestion of not string.replace('()',''):
if not string.replace('()', ''):
Let's take a look at what this does:
>>> not '()'.replace('()', '')
True
>>> not '()()'.replace('()', '')
True
>>> not '(()'.replace('()', '')
False
>>> not '(pie)'.replace('()', '')
False
Last, you shouldn't call a variable string because it shadows a module in the standard library. Something like user_given_string might work.
Summing it all up:
def recursion():
user_given_string = input("Enter your string: ")
if not user_given_string.replace('()', ''):
print("The string is even.")
else:
print("The string is not even.")

How do I ensure that a string will return properly in python?

I was building a bit of code that would trim off any non-digit entries from the start and end of a string, I had a very confusing issue with the following bit of code:
def String_Trim(Raw_String):
if Raw_String[0].isdigit() == False:
New_String = Raw_String[1:]
String_Trim(New_String)
elif Raw_String[-1].isdigit() == False:
New_String = Raw_String[:-1]
String_Trim(New_String)
else:
print Raw_String
return Raw_String
print(String_Trim('ab19fsd'))
The initial printing of Raw_String works fine and displays the value that I want (19), but for some reason, the last line trying to print the return value of String_Trim returns a None. What exactly is python doing here and how can I fix it? Any other comments about improving my code would also be greatly appreciated.
Use regex for this. Recursion for trimming a string is really not a good idea:
import re
def trim_string(string):
return re.sub(r'^([^0-9]+)(.*?)([^0-9]+)$', r'\2', string)
To break it down, the regex (r'^([^0-9]+)(.*?)([^0-9]+)$') is like so:
^ matches the start of a string.
([^0-9]+) matches a group of consecutive non-digit characters.
(.*?) matches a group of stuff (non-greedy).
([^0-9]+) matches another group of consecutive non-digit characters.
$ matches the end of the string.
The replacement string, r'\2', just says to replace the matched string with only the second group, which is the stuff between the two groups of non-digit characters.
But if you're really sure you want to use your existing solution, you need to understand how recursion actually works. When you call return foo, the function returns foo as its output. If you don't call return, you return None automatically.
That being said, you need to return in every case of the recursion process, not just at the end:
def String_Trim(Raw_String):
if Raw_String[0].isdigit() == False:
New_String = Raw_String[1:]
return String_Trim(New_String)
elif Raw_String[-1].isdigit() == False:
New_String = Raw_String[:-1]
return String_Trim(New_String)
else:
print Raw_String
return Raw_String
You return a value in only one case inside StringTrim. Add return in front of the recursive calls:
return String_Trim(New_String)
That should fix it.
If I understand your question correctly, you want to return only the digits from a string; because "trim of any non digits from the start and end" to me sounds like "return only numbers".
If that's correct, you can do this:
''.join(a for a in 'abc19def' if a.isdigit())

Categories