This is my code:
def redact_words(sentence):
redacted_sentence = sentence.split()
for word in redacted_sentence[2::3]:
for i in word:
if i.isalpha():
word.replace(i, '#')
else:
continue
return " ".join(redacted_sentence)
if the input is sentence = "You cannot drink the word 'water'."
the output should be "You cannot ##### the word '#####'."
The output I get is just a list of the words in my input.
We can accomplish this with a little Python magic:
def redact_words(sentence):
redacted_sentence = []
sentence = sentence.split()
for pos, word in enumerate(sentence, start=1):
if pos % 3 == 0:
word = "".join("#" if letter.isalpha() else letter for letter in word)
redacted_sentence.append(word)
return " ".join(redacted_sentence)
First, we create a list to contain the words of the new sentence. Next, after splitting the sentence into a list, we use enumerate
to generate the positions of each word in the sentence, along with the word itself. By starting at 1, we can use the modulus operator to see if the position is evenly divisible by 3. If so, we use a comprehension to replace all the alphabetical characters in word
with #
, leaving the other characters alone, then reassign the results back to word
. Finally, we append the word to the redacted_sentence
list, regardless of whether it's been changed, and return a string with all the words joined together with a space.
You've got two issues that sum to the same problem: Creating and discarding mutated copies of the string, while leaving the original untouched. str.replace
must be assigned somewhere to be useful (usually reassigning word
in this case), but also, to update the original list
, you must reassign that index in the list
( word
is a separate alias to the object in the list
, but reassigning word just rebinds word
and breaks the aliasing, it doesn't change the contents of the list
). So the solution is:
replace
operationlist
at the same locationThe minimalist modification to your code that achieves this result while still following the same basic design is:
from itertools import count # So we can track the index to perform replacement at
def redact_words(sentence):
redacted_sentence = sentence.split()
for i, word in zip(count(2, 3), redacted_sentence[2::3]): # Track index and value
for c in set(word): # Change name to c; i is for indices, not characters/letters
# For minor efficiency gain, dedupe word so we don't replace same char over and over
if c.isalpha():
word = word.replace(c, '#') # Reassign back to word so change not lost
redacted_sentence[i] = word # Replace original word in list with altered word
return " ".join(redacted_sentence)
A faster solution would replace the inner loop with a single-pass regex substitution or (if only ASCII need be handled) str.translate
call, replacing O(n²)
work per word with O(n)
work, eg:
import re
from itertools import count # So we can track the index to perform replacement at
# Precompile regex that matches only alphabetic characters and bind its sub method
# while we're at it
replace_alpha = re.compile(r'[^\W\d_]').sub
def redact_words(sentence):
redacted_sentence = sentence.split()
for i, word in zip(count(2, 3), redacted_sentence[2::3]): # Track index and value
# Replace every alphabetic character with # in provided word and replace
# list's contents at same index
redacted_sentence[i] = replace_alpha('#', word)
return " ".join(redacted_sentence)
Here is a way you can do it.
def redact_words(sentence, red_acted_words=None):
if red_acted_words is None:
red_acted_words = sentence.split()[2::3]
for rword in red_acted_words:
j = "#" * len(rword)
sentence = sentence.split(rword)
sentence = j.join(sentence)
return sentence
redact_words("You cannot drink the word 'water'.", red_acted_words=["water", "drink"])
redact_words("You cannot drink the word 'water'.")
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.