0

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.

1
  • No, however, I think I have spotted a problem with my loop. Commented Dec 14, 2019 at 20:07

5 Answers 5

0

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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

Comments

0

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))

1 Comment

re.sub('(?i)(?<=[a-z])[a-z]', '_', title)?
0

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)

Comments

0

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 substitute.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.