slohth
slohth

Reputation: 3

Python: String manipulation difficulty

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

Answers (5)

nulladdr
nulladdr

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

Upvotes: 0

Daniel
Daniel

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

Robin Zigmond
Robin Zigmond

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

Joran Beasley
Joran Beasley

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

slohth
slohth

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

Related Questions