Victor Yip
Victor Yip

Reputation: 295

A basic python function to censor replace words in sentences

I am trying to build a simple function to censor a specific word in a sentence. For example "hello hello hi" to "***** ***** hi" if I feed censor("hello hello hi", "hello"). Assuming I will not receive punctuation and sentences with upper case letters or empty strings.

After researching online I understand there is simpler solution, for example:

def censor(text, word):
    return text.replace(word, "*" * len(word)) 

I still want to understand from a learning perspective, what I did wrong in the below more complicated code.

def censor(text,word):
    split_text = text.split()
    length = len(word)
    for item in split_text:
        if item == word:
            item = ("*" * length)
        else:
            item = item
    return " ".join(split_text)

Upvotes: 4

Views: 4358

Answers (5)

Mike - SMT
Mike - SMT

Reputation: 15226

The solution I came up with was a little simpler and gets the job done.

1.I make sure both arguments are a string and then check if the word is in the text string. 2.Then if the word is in the text string I get the length of the word. 3.Then I replace the word inside the string with * however many times the word is long.

def censor(text,word):
t=str(text)
w=str(word)
if w in t:
    l=len(w)
    item = ("*" * l)
    return t.replace(w,item)
else:
    return t

Upvotes: 2

innoSPG
innoSPG

Reputation: 4656

There is a difference between the variable and the value that the variable has at a given point at the running time. The statement

for item in split_text:

Sequentially assigns the value of each item in split_text to item.

item = ("*" * length)

Changes item to a new value computed from its length. But split_text remains exactly what it was at the beginning.

Upvotes: 0

changhwan
changhwan

Reputation: 1112

As mentioned other answers, you can't change list value in for loop.

You can access list value using enumerate, get index of value. And, you don't need else because you don't change value.

for idx, item in enumerate(split_text):
    if item == word:
        split_text[idx] = ("*" * length)

Upvotes: 1

Michael S Priz
Michael S Priz

Reputation: 1126

You probably see what you did wrong based on the comments. But you might not understand why (and based on your question I think you may be interested to know).

In python you can roughly divide the datatypes into 2 categories: mutable and immutable. The basic difference is that you can create references to mutable type variables whereas you can only pass around the values of immutable type variables. Refer to this question for examples.

In your case you are iterating through a list containing strings. Strings happen to be immutable. So when you change item it won't have any effect on the corresponding element in split_text.

If instead you were iterating through a list of lists, you would actually be able to change the list elements using the placeholder variable.

Illustrated with an example:

x = [["foo"],["foo","bar"]]
for i in x:
    if len(i) == 1:
        i[0] += "bar"
    else:
        i.append("foobar")
print(x) #[["foobar"],["foo","bar","foobar"]]  

Hope this helps! :)

Upvotes: 1

deezy
deezy

Reputation: 1480

The for-loop in your code does not reference or modify the actual item in split_text. Try this:

for item in range(len(split_text)):
        if item == word:
            split_text[item] = ("*" * length)
            ...

Also, it is generally considered poor practice to modify a list within a loop. See this post: How to modify list entries during for loop?

Upvotes: 1

Related Questions