Stuck on Censor: indexing the splitted text


#1



https://www.codecademy.com/courses/python-intermediate-en-rCQKw/1/4?curriculum_id=4f89dab3d788890003000096#


I having trouble replacing the item in my splitted text with "*"
the console throws this error: TypeError: list indices must be integers, not str

Any hints on how to make this approach work?


def censor(text,word):
	text_split = text.split() 
	print text_split
	print word
	new = ""
	for item in text_split: #loop through words in list
		if text_split[item] == word: #if it equals the word then replace it
		   text_split[item] = "*" * len(word)
                else:
		   item = item #if it doesn't equal the word then leave it
	new = new.join(text_split)
	return new 
print censor("hack wack hack", "hack")


#2

item will contain the words, not indexes. You can just check if item equals word.

given what you do next, its more advisable to use range() which will give you indexes


#3

Using range() made it work: see below.
Also realised I didn't need the 'else' statement

def censor(text,word):
  text_split = text.split() 
  new = ""
  for item in range(len(text_split)): #loop through words in list
    if text_split[item] == word:
        text_split[item] = "*" * len(word)
  new = " ".join(text_split)
  return new
print censor("heya hey", "hey")

Curious if this approach could be simplified further, any ideas?


#4

you could get rid of this line:

new = ""

for the rest, not really. Its a good solution :slight_smile:


#5

Sweet, thanks!

Now I'm trying to nudge it up and make it also work if the censored word is part of a longer word. E.g. 'hey' in 'oheyla'
I think I can't use split and am therefore trying to solve it with nested if statements.
However I think I'm in the wrong direction, and my code keeps throwing these errors; "string index out of range"
Should I take a different approach or do you know a way to fix the error? (or both :slight_smile: )

def censor(text,word):
    index = 0
    lst = []
    for char in text:
        if char != word[index]:
            lst.append(text[index])
            index += 1
        elif char == word[index]:
            if text[index: index + len(word)] == word:
                lst.append("*" * len(word))
                index = index + 1 * len(word)
            else:
                lst.append(text[index])
                index += 1
        text = " ".join(lst)

censor("oheya hey hey ola", "hey")

#6

if you want to achieve this, you can use the build in replace() function. kind of dull though

you could also "hack" split, split on the word you want to censor:

 text_split = text.split(word)

now you can just join it together with asterixs.

It just: how much built in function do you want to use


#7

:slight_smile: I'll first try the dull approach and then the more 'hacky' one.

But one question about my old attempt that I don't understand.
I get an " IndexError: string index out of range " , only the second time it loops through the code on one particular line.
While in my mind the index should just have been increased by 1 and text[index] should equal text[1]

def censor(text,word):
    index = 0
    lst = []
    for char in text: 
        if char != word[index]:
            lst.append(text[index]) #Why do I get an out range error the second time it loops through this line??
            index += 1

#8

here:

if char != word[index]:

you use word[index], why?


#9

My approach is:
loop through text,
if the character doesn't match word[0]: append it to a list that we later join.
if char matches word[0] start checking if it's the whole word
if so, use replace() to replace with "*" * len(word) length, and append those to the list

I posted the first part of that code. Realize I could have used word[0]. But even if I do so I get the out of range error.
It puzzles me because in my mind index has become 1, and text[1] is valid.

I do get that I started off on a wrong very elaborate approach. What would you normally do, abandon it and start thinking from scratch?

By the way, highly appreciate your help!


#10

i would ditch it, and use split() instead, so you can break text into individual words which you can compare with word


#11

See your point in using replace()

def censor2(text, word):
    text_replace = text.replace(word, (len(word) * "*"))
    return text_replace

Very simple, yet less challenging

I also did have a second look at my earlier failed attempt to solve it with a FOR loop
It was a good idea to ditch it and start afresh.
Just sharing the code that worked for reference matters. Thanks for your feedback!

def censor(text, word):
    index = 0
    word_lst = list(word)
    text_lst = list(text)
    asterix_lst = [] 
    for item in range(len(word_lst)):
        asterix_lst.append("*")
    for index in range(len(text_lst)):
        if text_lst[index : (index + len(word))] == word_lst:
            text_lst[index : (index + len(word))] = asterix_lst
        new_text = "".join(text_lst)
    return new_text

#12

replace() is not perfect, if you want to censor go, going would become **ing

remember battle ships? i would use this trick here:

asterix_lst = [] 
    for item in range(len(word_lst)):
        asterix_lst.append("*")

then becomes:

asterix_list = ["*"] * len(word)

and i would place this:

new_text = "".join(text_lst)

outside the loop, you only need to join the list into a string once, at the end.


#13

You can use:

for index, item in enumerate(text):

Then you can track both index and the item to compare with the word using the following:

text[index:index+len(word)]==word


#14

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.