Reputation: 29
I'm trying to do a couple things with my code and I am confused as to how to interact with the elements of an array. The point of this code is to take a string as an input and redact certain words.
My goals are:
Have my program redact multiple words.
Make a new redacted string and save it as a variable, rather than just printing it to the console
I've outlined my logic using comments (couple of questions in the comments too).
puts "Write something: "
text = gets.chomp
puts "Redact some words: "
redact = gets.chomp
words = text.split(" ") #Turns string into array of words
redact_words = text.split(" ")
words.each do |word| #Iterates through each component of array [words] and permanently
word.downcase! #makes the placeholder (word) lower case.
end #Apparently this works also: words.map!(&:downcase) to make it
#undercase but I'm not sure why? What is .map? What is &:?
words.each do |word|
if redact_words.include?(word) #iterates through each component of array [redact_words] and
#checks if it includes the placeholder (word). If it does,
text.gsub!("#{word}","REDACTED") # it permanently globally substitutes the string of placeholder
#(word) with the string "REDACTED".
else puts "No redactable word(s) found"
end
end
puts text
My code isn't working that well however because its not seeing capitalization.
If you put in "Hello hello Okay okay" as the first input. And "hello okay" as the second input. You get "Hello REDACTED Okay REDACTED as the output.
I think its because its printing the modified string text and NOT the array [words] (which is kind of what I want because I want the redacted string to be saved to a variable). Is there another way to do this?
Also, is there a way to do the substitution I did except use regexp (regular expressions)?
Upvotes: 1
Views: 415
Reputation: 2916
To answer your question as to why words.map!(&:downcase)
works:
each
, map
loops over each item in an array passing that item to the given block. The difference is that it creates a new array with the returned items. map!
replaces the items in the current array with the returned items instead of creating a new array. reference&:downcase
is a shortcut for {|x| x.downcase }
. It essentially calls the specified method on each item in the array and uses the returned value as the new value.Here is a version of your script for you using regular expressions:
puts "Write something: "
text = gets.chomp
puts "Redact some words: "
redact = gets.chomp
redact_words = redact.split(" ")
# The %r syntax creates a regular expression using interpolation, the /i means to ignore case
new_text = text.gsub(%r/\b(#{redact_words.join('|')})\b/i, 'REDACTED')
puts "No redactable word(s) found" if new_text == text
puts new_text
Upvotes: 1
Reputation: 37419
You should make your search case-insensitive.
The simplest way is to build a regular expression (using Regexp.union
), and then matching it to the whole string:
def redact(text, redact)
redact_words = redact.split(" ")
redact_patterns = redact_words.map { |word| /\b#{word}\b/i } # /i makes it case insensitive,
# \b makes it whole word only
text.gsub(Regexp.union(redact_patterns), 'REDACTED')
end
redact('Hello hello Okay okay', "hello okay")
# => "REDACTED REDACTED REDACTED REDACTED"
Upvotes: 0