Ruby redaction program logic? - ruby

Okay,
I am doing the codeacademy ruby track and I am not stock with the problem.
I can make it works now, but I don't understand why it works.
instructions for exercise:
Let's start simple: write an .each loop that goes through words and just prints out each word it finds.
I have broken the problem into steps to try to understand why it works
but I am very confused.
My code for the problem is:
puts "Text to search through: " #ask user for input
text = gets.chomp
#store the user's input into the variable text
puts "Text to be reducted: "
#ask the user for input
redact = gets.chomp
#store the user's input into the variable redact
words = text.split(" ")
=begin
split the user's input into the variable words
store that input into the variable words
=end
words.each do |word|
=begin
creates a placeholder for the user's input
then attach an expression to the input stored in
the variable words one at a time. The variable
words holds the value of the variable text
=end
if word != redact
=begin
if word (which now holds the value of words that's
stored in the variable text, and which is the user's input)
is not equal to the value of the variable redact do something
=end
word = word + " "
=begin
increment the value of word by an empty space
why do I need to increment the value of word by an empty space?
=end
print "#{word}" #print the value of the variable word
else
print "REDACTED" #otherwise, print the value redacted
end
end
The program works if I use a string separated by an space and only if I change
word = word + ""
instead of
word = word + " "
I would truly appreciate if someone break it down for me, step by step.
I created a video of it for a more visual explanation of it.
here is the link: ruby redaction video
thank you.

The problem in your video is that "nelson" is not the same as "nelson ", and the Codeacademy scoring doesn't see a match when you append a space to the word before printing it.

I am reading this problem in July 2019..
So anybody who is reading this problem and getting confused with the below part asked by the user:
word = word + " "
=begin
increment the value of word by an empty space
why do I need to increment the value of word by an empty space?
So the answer is that the + sign is not for incrementing the value it's for adding a space and the + sign is used as string concatenator. So it has been placed there so that whatever words are being searched and displayed, they have a space between them.

Related

Can anyone explain me what is happening in 9th line "words.each do|word|"? why it is not words in the pipe why it's word?

puts "Text please: "
text = gets.chomp
puts "Redacted letter: "
redacted = gets.chomp
words = text.split(" ")
words.each do|word|
if word == redacted
print "REDACTED "
else
print word +" "
end
end
Can anyone explain me what is happening in 9th line, words.each do |word|? why it is not words in the pipe why it's word?
And if i want to print out "REDACTED" as output what i have to do?
please need help.
words is the whole list (of words found by splitting up the input text wherever there's a space) . More technically, it's an instance of the class Array, which has a method named each designed to run some block of code repeatedly - once for every element of the array. In this case, that means once per word in the input text.
Your snippet is calling each on words and passing a block of code to it - that's the do...end construct. (Code blocks can also be delimited by curly braces, {...}.)
The first thing inside the code block after the keyword do is a list of parameter names inside pipes. When the block is executed, any arguments passed to it will be given names from that list, in order.
Every time Array#each runs the block, it passes a single element of the array as an argument. In this case, that element will be assigned to a local variable named word within the body of the block.
So everything from do through end happens multiple times - once for every word in the array. The first time, word holds the first word. The second time, it holds the second word. And so on.
words never changes; it always holds the whole array.
You could, if you wanted, use the name words inside the block as well; it would be confusing, and the code in the block would not be able to access the outer words, but that outer words would still be intact at the end of the loop.
Sample run:
Code> puts "Text please: "
Output> Text please:
Code> text = gets.chomp
Input> Now is the time for all good men to come to the aid of their party.
Result> text == "Now is the time for all good men to come to the aid of their party."
Code> puts "Redacted letter: "
Output> Redacted letter:
Code> redacted = gets.chomp
Input> good
Result> redacted == "good"
Code> words = text.split(" ")
Result> words == [ "Now", "is", "the", "time", "for", "all", "good",
"men", "to", "come", "to", "the", "aid", "of", "their",
"party." ]
Code> words.each do |word|
Result> word == "Now"
Code> if word == redacted
Result> if "Now" == "good" #=> false
Code> else
Code> print word +" "
Output> "Now "
Code> words.each do |word|
Result> word == "is"
Code> if word == redacted
Result> if "is" == "good" #=> false
Code> else
Code> print word +" "
Output> "is " (Cumulative output: "Now is ")
.... and so on for "the", "time", "for", "all" ...
Code> words.each do |word|
Result> word == "good"
Code> if word == redacted
Result> if "good" == "good" #=> true
Code> print "REDACTED "
Output> "REDACTED "
... and so on for men, to, come, to, the, aid, of, their, party.
Code> end
Cumulative Output> Now is the time for all REDACTED men to come to the aid of their party.
To answer your questions succinctly. You ask three questions...
1) "what is happening in 9th line": In the beginning, you have this array of words, to which you apply .each. What this does is allows you to iterate over each element in the array. Each element is given to the word variable in the lines of code you have right after that do, and before the last end in your code (what you have there between the do and the last end is called a "block" of code, by the way).
2) "why it is not words in the pipe why it's word?" Well, this is Ruby syntax, really - the two things are different. The array you are iterating over is called words, and you want to do something with each one of those words in that array. People tend to use a plural for the name of container, like an array, and a singular when talking about "each" item in the array. So, when you say words.each, you tend to think of each one as a single "word". You could have used any name to represent a single element in the array called words, but word seems best.
3) "if i want to print out "REDACTED" as output": a) Run the code. b) When it asks for Text please:, give it one word (say "ABC" without quotes). c) When it then asks Redacted letter:, give it the same word (again, "ABC" without quotes). You should then be greeted with REDACTED.
Now that your stated questions are answered, if you want to go into learning why this happens, consider the if statement. You are going through each element in the array words, and seeing as how there is only one word ("ABC") this will only happen once. Since that "word" is exactly the same as the string currently in the variable redacted, the comparison turns out to be equal ("ABC" == "ABC"), and the command print "REDACTED " is run once and only once. If you had more words in the array, and none of them were "ABC", you'd also see those in your output
I'm glad you are learning Ruby. It's a great language! Keep up with it. You'll get better over time, and it's very rewarding.

What does word='word' and words=[] do in the following code?

I've been searching online. There are a lot of resources to explain the bigger concepts in the following code but not what the use and/or meaning is of the smaller details. What does the first two lines mean? (Also, I'm a beginner.)
word = 'word'
words =[]
puts 'Please type as many words per line then press the Enter Key.'
puts 'When you are finished press the Enter Key without typing anything.'
while word != ''
word = gets.chomp
words = words.push word
end
puts ''
puts 'Your original values:'
puts words
puts ''
puts 'Your values sorted:'
puts words.sort
puts ''
First:
word = 'word'
The part on the right initializes a new String object with the value "word". The part on the left and the equals sign make the variable word a reference to that string. Informally, this line assigns the string "word" to the variable word.
Next:
words = []
The part on the right initializes a new Array object. Since there's nothing between the square brackets, this creates an empty array. It's equivalent to Array.new. As above, the part on the left and the equals sign make the variable words a reference to the array. In other words, this line assigns the Array object to the variable words.

Error in .each execution (Ruby)

I'm making an auditor with ruby which started off fine this morning (using single word, user inputted content to omit) but now that I've tried to implement a wordlist, it puts the string to search through as many times as there are words in the wordlist, only censoring it once or twice. My code is as follows.
#by Nightc||ed, ©2015
puts "Enter string: "
text = gets.chomp
redact = File.read("wordlist.txt").split(" ")
words = text.split(" ")
redact.each do |beep|
words.each do |word|
if word != beep
print word + " "
else
print "[snip] "
end
end
end
sleep
I kind of understand why it doesn't work but I'm not sure how to fix it.
Any help would be appreciated.
There's an easier way than iterating through each array. The Array#include method can be easily used to see if the word is contained in your redacted list.
Here's some code that should behave how you wanted the original code to behave:
puts "Enter string: "
text = gets.chomp
redact = File.read("wordlist.txt").split(" ")
words = text.split(" ")
words.each do |word|
if redact.include? word
print "[snip] "
else
print word + " "
end
end
Scrubbing text gets very tricky. One thing you want to watch out for is word boundaries. Splitting on spaces will let a lot of beep words get through because of puctuation. Compare the first two results of the sample code below.
Next, assembling the split text back into its intended form with punction, spacing, etc., gets to be quite challenging. You may want to consider using regex for something presuambly as small as user comments. See the third result.
If you're doing this as a learning exercise, great, but if the application is sensitive where you're likely to take heat over failures to bleep words, you may want to look for an existing well-tested library.
#!/usr/bin/env ruby
# Bleeper
scifi_curses = ['friggin', 'gorram', 'fracking', 'dork']
text = "Why splitting spaces won't catch all the friggin bleeps ya gorram, fracking dork."
words = text.split(" ")
words.each do |this_word|
puts "bleep #{this_word}" if scifi_curses.include?(this_word)
end
puts
better_words = text.split(/\b/)
better_words.each do |this_word|
puts "bleep #{this_word}" if scifi_curses.include?(this_word)
end
puts
bleeped_text = text # keep copy of original if needed
scifi_curses.each do |this_curse|
bleeped_text.gsub!(this_curse, '[bleep]')
end
puts bleeped_text
You should get these results:
bleep friggin
bleep fracking
bleep friggin
bleep gorram
bleep fracking
bleep dork
Why splitting spaces won't catch all the [bleep] bleeps ya [bleep], [bleep] [bleep].

How to use "gets" and "gets.chomp" in Ruby

I learned that gets creates a new line and asks the user to input something, and gets.chomp does the same thing except that it does not create a new line. gets must return an object, so you can call a method on it, right? If so, lets name that object returned by gets as tmp, then you can call the chomp method of tmp. But before gets returns tmp, it should print a new line on the screen. So what does chomp do? Does it remove the new line after the gets created it?
Another way to re-expound my question is: Are the following actions performed when I call gets.chomp?
gets prints a new line
gets returns tmp
tmp.chomp removes the new line
User input
Is this the right order?
gets lets the user input a line and returns it as a value to your program. This value includes the trailing line break. If you then call chomp on that value, this line break is cut off. So no, what you have there is incorrect, it should rather be:
gets gets a line of text, including a line break at the end.
This is the user input
gets returns that line of text as a string value.
Calling chomp on that value removes the line break
The fact that you see the line of text on the screen is only because you entered it there in the first place. gets does not magically suppress output of things you entered.
The question shouldn't be "Is this the right order?" but more "is this is the right way of approaching this?"
Consider this, which is more or less what you want to achieve:
You assign a variable called tmp the return value of gets, which is a String.
Then you call String's chomp method on that object and you can see that chomp removed the trailing new-line.
Actually what chomp does, is remove the Enter character ("\n") at the end of your string. When you type h e l l o, one character at a time, and then press Enter gets takes all the letters and the Enter key's new-line character ("\n").
1. tmp = gets
hello
=>"hello\n"
2. tmp.chomp
"hello"
gets is your user's input. Also, it's good to know that *gets means "get string" and puts means "put string". That means these methods are dealing with Strings only.
chomp is the method to remove trailing new line character i.e. '\n' from the the string.
whenever "gets" is use to take i/p from user it appends new line character i.e.'\n' in the end of the string.So to remove '\n' from the string 'chomp' is used.
str = "Hello ruby\n"
str = str.chomp
puts str
o/p
"Hello ruby"
chomp returns a new String with the given record separator removed from the end of str (if present).
See the Ruby String API for more information.
"gets" allows user input but a new line will be added after the string (string means text or a sequence of characters)
"gets.chomp" allows user input as well just like "gets", but there is
not going to be a new line that is added after the string.
Proof that there are differences between them:
Gets.chomp
puts "Enter first text:"
text1 = gets.chomp
puts "Enter second text:"
text2 = gets.chomp
puts text1 + text2
Gets:
puts "Enter first text:"
text1 = gets
puts "Enter second text:"
text2 = gets
puts text1 + text2
Copy paste the code I gave you, run and you will see and know that they are both different.
For example:
x = gets
y = gets
puts x+y
and
x = gets.chomp
y = gets.chomp
puts x+y
Now run the two examples separately and see the difference.

How to receive data from user without ruby adding an extra newline

I am trying to create a program that alphabetizes a users' word entries. However, inspection of the users entries reveals that ruby is for some reason adding a newline character to each word. For instance, If i enter Dog, Cat, Rabbit the program returns ["Cat\n", "Dog\n", "Rabbit\n"] How do i prevent this from happening?
words = []
puts "Enter a word: "
until (word = gets).to_s.chomp.empty?
puts "Enter a word: "
words << word
end
puts words.sort.inspect
Change your code to:
until (word = gets.chomp).empty?
The way you're doing it now:
(word = gets).to_s.chomp.empty?
gets the string from the keyboard input, but it isn't returned to your code until the user presses Return, which adds the new-line, or carriage-return + new-line on Windows.
to_s isn't necessary because you're already getting the value from the keyboard as a string.
chomp needs to be tied to gets if you want all the input devoid of the trailing new-line or new-line/carriage-return. That will work fine when testing for empty?.
Ruby 2.4 has a solution for this:
input = gets(chomp: true)
# "abc"

Resources