I wrote a python function that should accept a string, and returns the same string with all even indexed characters in each word upper cased, and all odd indexed characters in each word lower cased.
E.g.: to_weird_case('Weird string case') # => returns 'WeIrD StRiNg CaSe'
def to_weird_case(string):
s = list(string.split(" "))
words = []
for word in s:
w = map(lambda x: x.upper() if word.index(x)%2 == 0 else x.lower(), word)
w = "".join(list(w))
words.append(w)
#print(words)
return " ".join(words)
Now to my problem: As soon as more than one word is passed, the last letters of the last word are all converted to uppercase and I don't understand why...
E.g.: to_weird_case('This is a testii') returns ThIs Is A TeSTII
Thanks for help
This is because the index() function returns the index of the first instance of that character in a string. What you want is to write your loop using enumerate:
for index, word in enumerate(s):
With this, rather than use the index function, you can write your logic based on the index variable passed from enumerate().
Related
Suppose that I have a string that I would like to modify at random with a defined set of options from another string. First, I created my original string and the potential replacement characters:
string1 = "abcabcabc"
replacement_chars = "abc"
Then I found this function on a forum that will randomly replace n characters:
def randomlyChangeNChar(word, value):
length = len(word)
word = list(word)
# This will select the distinct index for us to replace
k = random.sample(range(0, length), value)
for index in k:
# This will replace the characters at the specified index with the generated characters
word[index] = random.choice(replacement_chars)
# Finally print the string in the modified format.
return "".join(word)
This code does what I want with one exception -- it does not account for characters in string1 that match the random replacement character. I understand that the problem is in the function that I am trying to adapt, I predict under the for loop, but I am unsure what to add to prevent the substituting character from equaling the old character from string1. All advice appreciated, if I'm overcomplicating things please educate me!
In the function you retrieved, replacing:
word[index] = random.choice(replacement_chars)
with
word[index] = random.choice(replacement_chars.replace(word[index],'')
will do the job. It simply replaces word[index] (the char you want to replace) with an empty string in the replacement_chars string, effectively removing it from the replacement characters.
Another approach, that will predictably be less efficient on average, is to redraw until you get a different character from the original one:
that is, replacing:
word[index] = random.choice(replacement_chars)
with
char = word[index]
while char == word[index]:
char = random.choice(replacement_chars)
word[index] = char
or
while True:
char = random.choice(replacement_chars)
if char != word[index]:
word[index] = char
break
WARNING: if replacement_chars only features 1 character, both methods would fail when the original character is the same as the replacement one!
I hope everyone is safe.
I am trying to go over a string and capitalize every first letter of the string.
I know I can use .title() but
a) I want to figure out how to use capitalize or something else in this case - basics, and
b) The strings in the tests, have some words with (') which makes .title() confused and capitalize the letter after the (').
def to_jaden_case(string):
appended_string = ''
word = len(string.split())
for word in string:
new_word = string[word].capitalize()
appended_string +=str(new_word)
return appended_string
The problem is the interpreter gives me "TypeError: string indices must be integers" even tho I have an integer input in 'word'. Any help?
thanks!
You are doing some strange things in the code.
First, you split the string just to count the number of words, but don't store it to manipulate the words after that.
Second, when iterating a string with a for in, what you get are the characters of the string, not the words.
I have made a small snippet to help you do what you desire:
def first_letter_of_word_upper(string, exclusions=["a", "the"]):
words = string.split()
for i, w in enumerate(words):
if w not in exclusions:
words[i] = w[0].upper() + w[1:]
return " ".join(words)
test = first_letter_of_word_upper("miguel angelo santos bicudo")
test2 = first_letter_of_word_upper("doing a bunch of things", ["a", "of"])
print(test)
print(test2)
Notes:
I assigned the value of the string splitting to a variable to use it in the loop
As a bonus, I included a list to allow you exclude words that you don't want to capitalize.
I use the original same array of split words to build the result... and then join based on that array. This a way to do it efficiently.
Also, I show some useful Python tricks... first is enumerate(iterable) that returns tuples (i, j) where i is the positional index, and j is the value at that position. Second, I use w[1:] to get a substring of the current word that starts at character index 1 and goes all the way to the end of the string. Ah, and also the usage of optional parameters in the list of arguments of the function... really useful things to learn! If you didn't know them already. =)
You have a logical error in your code:
You have used word = len(string.split()) which is of no use ,Also there is an issue in the for loop logic.
Try this below :
def to_jaden_case(string):
appended_string = ''
word_list = string.split()
for i in range(len(word_list)):
new_word = word_list[i].capitalize()
appended_string += str(new_word) + " "
return appended_string
from re import findall
def capitalize_words(string):
words = findall(r'\w+[\']*\w+', string)
for word in words:
string = string.replace(word, word.capitalize())
return string
This just grabs all the words in the string, then replaces the words in the original string, the characters inside the [ ] will be included in the word aswell
You are using string index to access another string word is a string you are accessing word using string[word] this causing the error.
def to_jaden_case(string):
appended_string = ''
for word in string.split():
new_word = word.capitalize()
appended_string += new_word
return appended_string
Simple solution using map()
def to_jaden_case(string):
return ' '.join(map(str.capitalize, string.split()))
In for word in string: word will iterate over the characters in string. What you want to do is something like this:
def to_jaden_case(string):
appended_string = ''
splitted_string = string.split()
for word in splitted_string:
new_word = word.capitalize()
appended_string += new_word
return appended_string
The output for to_jaden_case("abc def ghi") is now "AbcDefGhi", this is CammelCase. I suppose you actually want this: "Abc Def Ghi". To achieve that, you must do:
def to_jaden_case(string):
appended_string = ''
splitted_string = string.split()
for word in splitted_string:
new_word = word.capitalize()
appended_string += new_word + " "
return appended_string[:-1] # removes the last space.
Look, in your code word is a character of string, it is not index, therefore you can't use string[word], you can correct this problem by modifying your loop or using word instead of string[word]
So your rectified code will be:
def to_jaden_case(string):
appended_string = ''
for word in range(len(string)):
new_word = string[word].capitalize()
appended_string +=str(new_word)
return appended_string
Here I Changed The Third Line for word in string with for word in len(string), the counterpart give you index of each character and you can use them!
Also I removed the split line, because it's unnecessary and you can do it on for loop like len(string)
I am constructing a chatbot that rhymes in Python. Is it possible to identify the last vowel (and all the letters after that vowel) in a random word and then append those letters to another string without having to go through all the possible letters one by one (like in the following example)
lastLetters = '' # String we want to append the letters to
if user_answer.endswith("a")
lastLetters.append("a")
else if user_answer.endswith("b")
lastLetters.append("b")
Like if the word was right we’d want to get ”ight”
You need to find the last index of a vowel, for that you could do something like this (a bit fancy):
s = input("Enter the word: ") # You can do this to get user input
last_index = len(s) - next((i for i, e in enumerate(reversed(s), 1) if e in "aeiou"), -1)
result = s[last_index:]
print(result)
Output
ight
An alternative using regex:
import re
s = "right"
last_index = -1
match = re.search("[aeiou][^aeiou]*$", s)
if match:
last_index = match.start()
result = s[last_index:]
print(result)
The pattern [aeiou][^aeiou]*$ means match a vowel followed by possibly several characters that are not a vowel ([^aeiou] means not a vowel, the sign ^ inside brackets means negation in regex) until the end of the string. So basically match the last vowel. Notice this assumes a string compose only of consonants and vowels.
My code suppose to take a string to a function and then switch the caps of each char in there from h to H and E to e
but I somewhat get an error in my if s
why is that?
This is the error messege:
chr = str[i]
TypeError: string indices must be integers, not str
My code is:
def CapsChanger(str):
i = str[0]
for i in str :
chr = str[i]
if((ord(chr) > 46) and (ord(chr) < 91)):
str[i].upper()
if((ord(chr) > 96) and (ord(chr) < 126)):
str[i].lower()
print str
str = raw_input()
CapsChanger(str)
input()
When you do for i in str, in each iteration i represents that actual character, not the index. So you don't need to do chr = str[i] - i is already that character.
import string
def invertCase(text):
## Creating a list where results will be stored
results = list()
## This will contain the abc in upper and lowercase: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
abc = string.lowercase + string.uppercase
## Looping each letter of the received text
for letter in text:
## If the current letter of the loop exists in our abc variable contents, it means it's a letter and not a symbol or space
## So we can apply upper() or lower() to the letter.
if letter in abc:
## If the letter is currently uppercase, then we turn it into lowercase
if letter.isupper():
results.append(letter.lower())
## If the letter is currently lowercase, then we turn it into uppercase
else:
results.append(letter.upper())
## The current letter of the loop is not in our abc variable so it could be anything but a letter
## So we just append it to our results list
else:
results.append(letter)
## Once the loop finishes we just join every item in the list to make the final string and return it
return ''.join(results)
print invertCase('SoMeOnE Is hAvING fUN')
Output:
sOmEoNe iS HaVing Fun
The variable i is already a 1 character string because the for loop processes strings this way. Also, when you call str[i].upper(), it needs to either be assigned to something, or printed out, otherwise the character is never actually changed in place. .lower() and .upper() also have a behaviour which already checks the range for you, and returns the same characters. Eg. if it already uppercase, or a number, upper() will just return the same character.
Your function can be simplified as follows:
import sys
def CapsChanger(str):
for i in str:
sys.stdout.write (i.lower() if (i.upper() == i) else i.upper())
print
str = raw_input()
CapsChanger(str)
sys.stdout.write is used to avoid printing out extra spaces. The ternary operator is used to switch case in one shot:
<value1> if <condition> else <value2>
i is a string, not index. If You need index use enumerate:
for idx, i in str:
print idx, i
Insted of ord(chr) use string that represent a letter.
Insted of two if conditions use Chained Comparisons.
def CapsChanger(str):
out = []
for idx,chr in enumerate(str):
if 'Z' >= chr >= 'A':
out.append(chr.lower())
elif 'z' >= chr >= 'a':
out.append(chr.upper())
print(''.join(out))
I have a homework question which asks to read a string through raw input and count how many vowels are in the string. This is what I have so far but I have encountered a problem:
def vowels():
vowels = ["a","e","i","o","u"]
count = 0
string = raw_input ("Enter a string: ")
for i in range(0, len(string)):
if string[i] == vowels[i]:
count = count+1
print count
vowels()
It counts the vowels fine, but due to if string[i] == vowels[i]:, it will only count one vowel once as i keeps increasing in the range. How can I change this code to check the inputted string for vowels without encountering this problem?
in operator
You probably want to use the in operator instead of the == operator - the in operator lets you check to see if a particular item is in a sequence/set.
1 in [1,2,3] # True
1 in [2,3,4] # False
'a' in ['a','e','i','o','u'] # True
'a' in 'aeiou' # Also True
Some other comments:
Sets
The in operator is most efficient when used with a set, which is a data type specifically designed to be quick for "is item X part of this set of items" kind of operations.*
vowels = set(['a','e','i','o','u'])
*dicts are also efficient with in, which checks to see if a key exists in the dict.
Iterating on strings
A string is a sequence type in Python, which means that you don't need to go to all of the effort of getting the length and then using indices - you can just iterate over the string and you'll get each character in turn:
E.g.:
for character in my_string:
if character in vowels:
# ...
Initializing a set with a string
Above, you may have noticed that creating a set with pre-set values (at least in Python 2.x) involves using a list. This is because the set() type constructor takes a sequence of items. You may also notice that in the previous section, I mentioned that strings are sequences in Python - sequences of characters.
What this means is that if you want a set of characters, you can actually just pass a string of those characters to the set() constructor - you don't need to have a list one single-character strings. In other words, the following two lines are equivalent:
set_from_string = set('aeiou')
set_from_list = set(['a','e','i','o','u'])
Neat, huh? :) Do note, however, that this can also bite you if you're trying to make a set of strings, rather than a set of characters. For instance, the following two lines are not the same:
set_with_one_string = set(['cat'])
set_with_three_characters = set('cat')
The former is a set with one element:
'cat' in set_with_one_string # True
'c' in set_with_one_string # False
Whereas the latter is a set with three elements (each one a character):
'c' in set_with_three_characters` # True
'cat' in set_with_three_characters # False
Case sensitivity
Comparing characters is case sensitive. 'a' == 'A' is False, as is 'A' in 'aeiou'. To get around this, you can transform your input to match the case of what you're comparing against:
lowercase_string = input_string.lower()
You can simplify this code:
def vowels():
vowels = 'aeiou'
count = 0
string = raw_input ("Enter a string: ")
for i in string:
if i in vowels:
count += 1
print count
Strings are iterable in Python.
for i in range(0, len(string)):
if string[i] == vowels[i]:
This actually has a subtler problem than only counting each vowel once - it actually only tests if the first letter of the string is exactly a, if the second is exactly e and so on.. until you get past the fifth. It will try to test string[5] == vowels[5] - which gives an error.
You don't want to use i to look into vowels, you want a nested loop with a second index that will make sense for vowels - eg,
for i in range(len(string)):
for j in range(len(vowels)):
if string[i] == vowels[j]:
count += 1
This can be simplified further by realising that, in Python, you very rarely want to iterate over the indexes into a sequence - the for loop knows how to iterate over everything that you can do string[0], string[1] and so on, giving:
for s in string:
for v in vowels:
if s == v:
count += 1
The inner loop can be simplified using the in operation on lists - it does exactly the same thing as this code, but it keeps your code's logic at a higher level (what you want to do vs. how to do it):
for s in string:
if s in vowels:
count += 1
Now, it turns out that Python lets do math with booleans (which is what s in vowels gives you) and ints - True behaves as 1, False as 0, so True + True + False is 2. This leads to a one liner using a generator expression and sum:
sum(s in vowels for s in string)
Which reads as 'for every character in string, count how many are in vowels'.
you can use filter for a one liner
print len(filter(lambda ch:ch.lower() in "aeiou","This is a String"))
Here's a more condensed version using sum with a generator:
def vowels():
string = raw_input("Enter a string: ")
print sum(1 for x in string if x.lower() in 'aeiou')
vowels()
Option on a theme
Mystring = "The lazy DOG jumped Over"
Usestring = ""
count=0
for i in Mystring:
if i.lower() in 'aeiou':
count +=1
Usestring +='^'
else:
Usestring +=' '
print (Mystring+'\n'+Usestring)
print ('Vowels =',count)
The lazy DOG jumped Over
^ ^ ^ ^ ^ ^ ^
Vowels = 7