Reputation: 3
I have a function here which should change every letter in the string, apart from the first letter of each word, to an underscore. However, it does not seem to work.
def nameManipulate(title):
positions = []
for letter in range(len(title)):
if title[letter] == " ":
positions.append(letter+1)
positions.insert(0, 0)
print(positions) # Positions of first word of each letter in the string
for letter in range(len(title)):
if letter not in positions: # If the letter is not in the list
new_title = title.replace(str(title[letter]), "_") # Replace the letter with an underscore
return new_title
displayTitle = str(nameManipulate(title))
(the title variable has already been declared and works fine)
The code however doesn't seem to work. It creates an array of positions of all the letters which are at the beginning of the word and changes all those not in that list to an underscore, or should, in theory.
However, when I run the code, this is the output.
(The title in this case was "Jonny B Good")
[0, 6, 8]
Jonny B Goo_
Any help would be greatly appreciated, thank you.
Upvotes: 0
Views: 93
Reputation: 561
Just use regex.
import re
print( re.sub(r"((?<!\b)\w+)", lambda m: len(m.group(1))*"_", "Johnny B Goode") )
(?<!\b)\w+
(negative lookbehind) matches one or more characters \w+
that is not preceded by an \b
(word boundary), m
in lambda m: ...
is re.Match
object which contains groups we matched with ()
(capturing group), we return "_"
repeated len(m.group(1))
times, and sub
stitute.
Upvotes: 0
Reputation: 42758
Your algorithm does not work correctly, if the one replaced character is also a starting character.
def nameManipulate(title):
result = []
replace = False
for character in title:
if character == " ":
replace = False
elif not replace:
replace = True
else:
character = "_"
result.append(character)
return "".join(result)
Upvotes: 0
Reputation: 18249
You're only actually replacing the last letter. That's because of your final loop and return
statement:
for letter in range(len(title)):
if letter not in positions: # If the letter is not in the list
new_title = title.replace(str(title[letter]), "_") # Replace the letter with an underscore
return new_title
You clearly intend new_title
to collect all the changes in the loop - but you're actually assigning it to the result of replace
on title
, which is the original string. As a result, the only change you ever see in the final value is the last one.
The solution is simple: just assign the value in the title
variable to new_title
before the loop starts, and use that string's replace
method. That way, new_title
will accumulate all the changes:
new_title = title
for letter in range(len(title)):
if letter not in positions: # If the letter is not in the list
new_title = new_title.replace(str(new_title[letter]), "_") # Replace the letter with an underscore
return new_title
This actually still won't work as intended in all cases, because replace
replaces the first occurrence of the given letter, not necessarily the one at the particular position you intend. I'll leave you to solve that yourself, but hopefully this helps you over that first hurdle.
Upvotes: 0
Reputation: 113988
I would just use regex for this
import re
title = "Johnny B Goode."
print(re.sub("([a-zA-Z])([a-zA-Z]+)",lambda m:m.group(1)+"_"*len(m.group(2)),title))
Upvotes: 0
Reputation: 3
Managed to fix it, it was a problem with the loop. Rather than:
for letter in range(len(title)):
if letter not in positions: # If the letter is not in the list
new_title = title.replace(str(title[letter]), "_") # Replace the letter with an underscore
You should declare the new_title variable first, and have it in all instances of the .replace method.
def nameManipulate(title):
positions = []
new_title = title
for letter in range(len(title)):
if title[letter] == " ":
positions.append(letter+1)
positions.insert(0, 0)
print(positions) # Positions of first word of each letter in the string
for letter in range(len(title)):
if letter not in positions: # If the letter is not in the list
if title[letter] != " ":
new_title = new_title.replace(str(title[letter]), "_") # Replace the letter with an underscore
return new_title
Upvotes: 0