How can I use split( ) to make censor?

Why doesn’t this work?

def censor(text, word):
  new_text = []
  text = text.split()
  print text
  for i in text:
    if i == word:
      new_text = new_text.append("*" * len(word))
    else:
      new_text = new_text.append(i)
  new_text = " ".join(new_text)
  return new_text
2 Likes

It looks like it should work. Is it not being accepted by the lesson checker? If not, then perhaps try it with the print statement removed.

2 Likes

You should probably examine what makes you say that it doesn’t work - you need to know what the difference in behaviour is before you can start looking for its reason. After that think about what should happen and start comparing with what does happen. Printing out messages/information from your function allows you to observe what’s going on.

2 Likes

I tried using the ‘range’ function instead of the ‘count’ variable and I’m not sure why it’s not working. It just prints out the full sentence without any censorship:

def censor(text, word):
    words = text.split()
    result = ''
    stars = '*' * len(word)
    for i in range(0, len(words)):
        if i == word:
          words[i] = stars
      
    result =' '.join(words)

    return result
  
print censor("this hack is wack hack", "hack")
1 Like

There could be a number of reasons for this. The most obvious one would be to check if the comparison:

if i == word:
   print "i get here"

oops, that doesn’t seem to happen. Lets check the value for comparisons:

for i in range(0, len(words)):
   print i, word

that explains a lot.

its important to teach yourself these thinking and debug steps. Of course a debug tool would be better.

2 Likes

Apologies - I don’t understand this

1 Like

i showed you print statements, which you can include in your code to help you identify the issue.

what do you not understand? Please be more specific.

2 Likes

Ah okay,

So you are checking if the ‘if’ statement and ‘for’ loop is functioning properly, correct?

1 Like

yes, that is step 1:

if i == word:
   print "i get here"

which lead me to the conclusion that the if condition isn’t functioning properly, given word is present in text.

so then i am checking why the if condition is not working properly:

for i in range(0, len(words)):
   print i, word
3 Likes
def censor(text, word):
  my_word_arr = []
  my_word_arr.append(word)
  word = "*" * len(word)
  only_text_arr = []
  my_final_yay = ""
  for i in text:
    num = 0
    if word in text:
      only_text_arr.append(text[num])
      
      if i == my_word_arr[num] and my_word_arr[num] == word[num]:
        only_text_arr.insert(my_word[num], word)
    num += 1
    my_final_yay += only_text_arr[num]
  return my_final_yay
#Let me test this Codecademy!
print censor("mmm bacon", "bacon")
#if word in text returns False for the first time?

1 Like

Is it any wonder?

That won’t be found anywhere in the text.

Again, you seem to be pulling at straws and making the process a lot more complicated than it needs to be. It’s one thing to experiment when we have an expectation; but, it is another entirely to be blindly running into walls. How much of that code can be stripped away (much like we did yesterday in your other thread)?

1 Like
def censor(text, word):
  arr = text.split()
  num = 0
  my_text = ""
  for t in arr:
    if word in text:
      if t == word:
        arr[arr.index(word)] = "*" * len(word)
        my_text += arr[num]
        my_text += " "
      elif t != word:
        my_text += arr[num]
        my_text += " "
    num += 1
  lst = []
  for n in my_text:
    lst.append(n)
  lst.remove(lst[len(lst)-1])#Should remove the last item of the array lst
  my_text = ""
  for item in lst:
    my_text += item
  return my_text
print censor("mmm bacon", "bacon")
>>> def censor(text, word):
    text = text.split()    # re-uses variable
    while True:
        try:
            text[text.index(word)] = "*" * len(word)
        except ValueError:
            return ' '.join(text)

>>> censor('the big brown bear ate the big fish', 'big')
'the *** brown bear ate the *** fish'
>>> 

Now you may not yet have leaned about exception handling so don’t stress over the above. I only used this method because index() raises a ValueError when a value is not found in the list. We’re leveraging that aspect of the method.

The point I’m making is that we base the technique on what components we plan on using. Rarely in such a problem as this do we need to implement several methods in one function. And when our approach gets bloated or unwieldly then it is a good sign we are overthinking the problem and getting our wires crossed somewhere.

Consider the .remove method. This problem is one that calls for replacement of every instance of some value. There is no indication that the method will be of any real value, so we should not reach for that one.

In a normal loop with no exception handling we would not use .index() without first checking for a match, such as your code does. There is actually a simpler way to pinpoint the exact index of the found word. Recall that .index() returns the first instance of the object, which is why the above example requires a loop to keep crawling over the text list looking for more matches. Only one match is replaced at a time.

Consider,

text = text.split()
for i, x in enumerate(text):    # i is the index, x is the value
    if x == word:
        text[i] = "*" * len(word)
return ' '.join(text

We choose our algorithm based on the method of our approach, and then refine it along that one line.

Consider the string method, which is no fun since there is no real algorithm that we can see (the method does all the work in the background)…

return text.replace(word, '*' * len(word))

Boom! Just like that. We chose the method, and stuck with it.

A little more work goes into the more naive approach, but we can still keep it simple…

result = []
for term in text.split():
    if term == word:
        result.append('*' * len(word))
    else:
        result.append(term)
return ' '.join(result)

I’m sure you can come up with a number of other approaches to this problem, and really should play around with it until you do. Keep it simple, and don’t be afraid to start from scratch when things look to be getting out of hand.

1 Like


why is my answer not being accepted. i think its technically correct. :confused: help

None indicates the absence of a return value, shouldn’t you return something?

Keep up the great work @mtf. :+1: Your explanations on everything I have read that you have posted on all different problems has helped me immensely. I am that way now that I go looking for your explanations first when I have a problem, which is nearly everyday. :grinning:

Just wanted to pass on my thoughts, Thanks again.

1 Like

Can we also do this exercise using the replace function? I tried like this:

def censor (text, word):
print text.replace (“word”, “*”, len(word)))

censor (“I do not like this exercise”, “not”)

But that does not work

you could use replace, but it has an issue:

censor("this hack is a wack hack", "is")

using replace would partial censor this to th**, which i think shouldn’t be. But there are no test cases covering this.

the instructions state to return the censored string

Because str.replace is for replacing characters in a string, not words in a sentence, we need a way to discover word boundaries. That is a job for regular expressions, which is as yet still beyond the scope of this exercise, but doable.

@appylpye, have you any insight to offer in this regard?

As much as we can our efforts should center around first performing the task (censor) using naive approaches such as interation and comparison. Learn to plan and write algorithms so you build upon that intuition rather that just learning the Python built in methods.

it is simpler to use the str.split() and str.join() methods than to resort to regular expressions. See the wealth of material at re — Regular expression operations.

We can do this:

import re
def censor(text, word):
  # match word surrounded by word boundaries by using \b
  regex = re.compile(r"\b" + word + r"\b")
  # substitute asterisks for word for each matching group within text
  result = regex.sub(lambda m: m.group().replace(word, "*" * len(word), 1), text)
  return result
1 Like