The 'reverse by characters' works but the third test "by words" doesn't -
expected: "sti gniniar"
got: "sti" (using ==)
def reverse_itti(msg, style='by_character')
new_string = ''
word = ''
if style == 'by_character'
msg.each_char do |one_char|
new_string = one_char + new_string
end
elsif style == 'by_word'
msg.each_char do |one_char|
if one_char != ' '
word+= one_char
else
new_string+= reverse_itti(word, 'by_character')
word=''
end
end
else
msg
end
new_string
end
describe "It should reverse sentences, letter by letter" do
it "reverses one word, e.g. 'rain' to 'niar'" do
reverse_itti('rain', 'by_character').should == 'niar'
end
it "reverses a sentence, e.g. 'its raining' to 'gniniar sti'" do
reverse_itti('its raining', 'by_character').should == 'gniniar sti'
end
it "reverses a sentence one word at a time, e.g. 'its raining' to 'sti gniniar'" do
reverse_itti('its raining', 'by_word').should == 'sti gniniar'
end
end
The problem is in this loop:
msg.each_char do |one_char|
if one_char != ' '
word+= one_char
else
new_string+= reverse_itti(word, 'by_character')
word=''
end
end
The else block reverses the current word and adds it to the output string, but it only runs when the loop encounters a space character. Since there is no space at the very end of the string, the last word is never added to the output. You can fix this by adding new_string+= reverse_itti(word, 'by_character') after the end of the loop.
Also, you probably want to add a space to the end of the output string in the else block, too.
Related
Hi I'm building a function that has me take any instance of "u" or "you" in a string and replace it with a specific word. I can go in and isolate the instances no problem but I cannot get the words to output properly. So far I have.
def autocorrect(input)
#replace = [['you','u'], ['your sister']]
#replace.each{|replaced| input.gsub!(replaced[0], replaced[1])}
input.split(" ")
if (input == "u" && input.length == 1) || input == "you"
input.replace("your sister")
end
input.join(" ")
end
The ideal output would be:
autocorrect("I am so smitten with you")
"I am smitten with your sister"
I don't know how to get the last part correct, I can't think of a good method to use. Any help would be greatly appreciated.
The problem you're having with your code is that you call input.split(" ") but you don't save that to anything, and then you check for input == "u" # ..., and input is still the entire string, so if you called autocorrect('u') or autocorrect('you') you would get "your sister" back, except for the next line: input.join(" ") will throw an error.
This error is because, remember input is still the original string, not an array of each word, and strings don't have a join method.
To get your code working with the fewest changes possible, you can change it to:
def autocorrect(input)
#replace = [['you','u'], ['your sister']]
#replace.each{|replaced| input.gsub!(replaced[0], replaced[1])}
input.split(" ").map do |word|
if (word == "u" && word.length == 1) || word == "you"
"your sister"
else
word
end
end.join(" ")
end
So, now, you are doing something with each word after you split(" ") the input, and you are checking each word against "u" and "you", instead of the entire input string. You then map either the replacement word, or the original, and then join them back into a single string to return them.
As an alternative, shorter way, you can use String#gsub which can take a Hash as the second parameter to do substitutions:
If the second argument is a Hash, and the matched text is one of its keys, the corresponding value is the replacement string.
def autocorrect(input)
replace = { 'you' => 'your sister',
'u' => 'your sister',
'another word' => 'something else entirely' }
input.gsub(/\b(#{replace.keys.join('|')})\b/, replace)
end
autocorrect("I am u so smitten with utopia you and another word")
# => "I am your sister so smitten with utopia your sister and something else entirely"
the regex in that example comes out looking like:
/\b(you|u|another word)\b/
with \b being any word boundary.
Simple array mapping would do the job:
"I am u so smuitten with utopia you".split(' ').map{|word| %w(you u).include?(word) ? 'your sister' : word}.join(' ')
#=> "I am your sister so smuitten with utopia your sister"
Your method would be:
def autocorrect(input)
input.split(' ').map{|word| %w(you u).include?(word) ? 'your sister' : word}.join(' ')
end
autocorrect("I am so smitten with you")
#=> "I am smitten with your sister"
I try to catch only cases b and d from sample below (ie. END should be the only word on a line (or at least be a word not part of longer word, and END should be at beginning of line (not necessarily ^, could start from column #2, case \i.)
I cannot combine this all togethernin one regex, can I have more then 1 flag in regex? I also need this OR in this regex too.
Thanks all.
M
regexDrop = /String01|String2|\AEND/i #END\n/i
a = "the long END not begin of line"
b = "ENd" # <#><< need this one
c = "END MORE WORDs"
d =" EnD" # <#><< need this one
if a =~ regexDrop then puts "a__Match: " + a else puts 'a_' end
if b =~ regexDrop then puts "b__Match: " + b else puts 'b_' end
if c =~ regexDrop then puts "c__Match: " + c else puts 'c_' end
if d =~ regexDrop then puts "d__Match: " + d else puts 'd_' end
## \w Matches word characters.
## \A Matches beginning of string. (could be not column 1)
Note that \A is an anchor (a kind of a built-in lookehind, or "zero width assertion", that matches the beginning of a whole string. The \w is a shorthand class matching letters, digits and an underscore (word characters).
Judging by your description and sample input and expected output, I think you are just looking for END anywhere in a string as a whole word and case-insensitive.
You can match the instances with
regexDrop = /String01|String2|\bEND\b/i
Here is a demo
Output:
a__Match: the long END not begin of line
b__Match: ENd
c__Match: END MORE WORDs
d__Match: EnD
I'm new to programming and I'm working with Ruby as my starter language. The below code works, but if someone inputs more than one word, the pigatize method only works on the first word and adds the additional ay or way to the last word. How do i get it to apply to each word a user inputs?
# If the first letter is a vowel, add "way" to the end
# If the first letter is a consonant, move it to the end and add "ay"
class PigLatin
VOWELS = %w(a e i o u)
def self.pigatize(text)
if PigLatin.vowel(text[0])
pigalatin = text + 'way'
else
piglatin = text[1..-1] + text[0] + 'ay'
end
end
def self.vowel(first_letter)
VOWELS.include?(first_letter)
end
end
puts 'Please enter a word and I will translate it into Pig Latin. Ippyyay!.'
text = gets.chomp
puts "Pigatized: #{PigLatin.pigatize(text)}"
Chiefly, you need to split the input string into words with String#split, using an expression like:
text.split(' ')
That produces an array of words, which you can loop over with an .each block and run the algorithm on each word, then reassemble them with += and a space at the end + ' '
Incorporating these things into your existing code looks like the following (with comments):
class PigLatin
VOWELS = %w(a e i o u)
def self.pigatize(text)
# Declare the output string
piglatin = ''
# Split the input text into words
# and loop with .each, and 'word' as the iterator
# variable
text.split(' ').each do |word|
if PigLatin.vowel(word[0])
# This was misspelled...
# Add onto the output string with +=
# and finish with an extra space
piglatin += word + 'way' + ' '
else
# Same changes down here...
piglatin += word[1..-1] + word[0] + 'ay' + ' '
end
end
# Adds a .chomp here to get rid of a trailing space
piglatin.chomp
end
def self.vowel(first_letter)
VOWELS.include?(first_letter)
end
end
puts 'Please enter a word and I will translate it into Pig Latin. Ippyyay!.'
text = gets.chomp
puts "Pigatized: #{PigLatin.pigatize(text)}"
There are other ways to handle this than adding to the string with +=. You could, for example add words onto an array with an expression like:
# piglatin declared as an array []
# .push() adds words to the array
piglatin.push(word + 'way')
Then when it's time to output it, use Array#join to connect them back with spaces:
# Reassemble the array of pigatized words into a
# string, joining the array elements by spaces
piglatin.join(' ')
There are alternatives to .each..do for the loop. You could use a for loop like
for word in text.split(' ')
# stuff...
end
...but using the .each do is a bit more idiomatic and more representative of what you'll usually find in Ruby code, though the for loop is more like you'd find in most other languages besides Ruby.
I've written a method for adding ay to the ends of words if they begin with a vowel. If the words begin with a consonant it will move the consonants to the end of the word and then add ay.
My issue with this is that my result is returned in an array for example:
translate("happy animals")
Instead of getting "appyhay animalsay"
I get ["appyhay", "animalsay"]
I tried joining them at the end, but when I run the test it says that the join method could not be found?
Is this just a mess or am I getting close?
Many thanks for any insight :)
def translate(word)
multiplewords = word.split(" ")
multiplewords.map! do |x|
separated = x.split("")
if !'aeiou'.include?(separated[0])
while !'aeiou'.include?(separated[0])
letter = separated.shift
separated << letter
separated
end
final = separated.join("") + "ay"
else
final = separated.join("") + "ay"
end
end
end
translate("happy animals") => ['appyhay', 'animlasay']
Answer needed: "appyhay animalsay"
You should join it at the last part. I tried to simplify it a bit as well.
#!/usr/bin/env ruby
def translate(word)
word.split(" ").map do |x|
separated = x.split("")
if !'aeiou'.include?(separated[0])
while !'aeiou'.include?(separated[0])
letter = separated.shift
separated << letter
end
end
separated.join("") + "ay"
end.join(' ')
end
puts translate("happy animals")
Output:
appyhay animalsay
I'm writing a short class to extract email addresses from documents. Here is my code so far:
# Class to scrape documents for email addresses
class EmailScraper
EmailRegex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
def EmailScraper.scrape(doc)
email_addresses = []
File.open(doc) do |file|
while line = file.gets
temp = line.scan(EmailRegex)
temp.each do |email_address|
puts email_address
emails_addresses << email_address
end
end
end
return email_addresses
end
end
if EmailScraper.scrape("email_tests.txt").empty?
puts "Empty array"
else
puts EmailScraper.scrape("email_tests.txt")
end
My "email_tests.txt" file looks like so:
example#live.com
another_example90#hotmail.com
example3#diginet.ie
When I run this script, all I get is the "Empty array" printout. However, when I fire up irb and type in the regex above, strings of email addresses match it, and the String.scan function returns an array of all the email addresses in each string. Why is this working in irb and not in my script?
Several things (some already mentioned and expanded upon below):
\z matches to the end of the string, which with IO#gets will typically include a \n character. \Z (upper case 'z') matches the end of the string unless the string ends with a \n, in which case it matches just before.
the typo of emails_addresses
using \A and \Z is fine while the entire line is or is not an email address. You say you're seeking to extract addresses from documents, however, so I'd consider using \b at each end to extract emails delimited by word boundaries.
you could use File.foreach()... rather than the clumsy-looking File.open...while...gets thing
I'm not convinced by the Regex - there's a substantial body of work already around:
There's a smarter one here: http://www.regular-expressions.info/email.html (clicking on that odd little in-line icon takes you to a piece-by-piece explanation). It's worth reading the discussion, which points out several potential pitfalls.
Even more mind-bogglingly complex ones may be found here.
class EmailScraper
EmailRegex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\Z/i # changed \z to \Z
def EmailScraper.scrape(doc)
email_addresses = []
File.foreach(doc) do |line| # less code, same effect
temp = line.scan(EmailRegex)
temp.each do |email_address|
email_addresses << email_address
end
end
email_addresses # "return" isn't needed
end
end
result = EmailScraper.scrape("email_tests.txt") # store it so we don't print them twice if successful
if result.empty?
puts "Empty array"
else
puts result
end
Looks like you're putting the results into emails_addresses, but are returning email_addresses. This would mean that you're always returning the empty array you defined for email_addresses, making the "Empty array" response correct.
You have a typo, try with:
class EmailScraper
EmailRegex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
def EmailScraper.scrape(doc)
email_addresses = []
File.open(doc) do |file|
while line = file.gets
temp = line.scan(EmailRegex)
temp.each do |email_address|
puts email_address
email_addresses << email_address
end
end
end
return email_addresses
end
end
if EmailScraper.scrape("email_tests.txt").empty?
puts "Empty array"
else
puts EmailScraper.scrape("email_tests.txt")
end
You used at the end \z try to use \Z according to http://www.regular-expressions.info/ruby.html it has to be a uppercase Z to match the end of the string.
Otherwise try to use ^ and $ (matching the start and the end of a row) this worked for me here on Regexr
When you read the file, the end of line is making the regex fail. In irb, there probably is no end of line. If that is the case, chomp the lines first.
regex=/\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
line_from_irb = "example#live.com"
line_from_file = line_from_irb +"/n"
p line_from_irb.scan(regex) # => ["example#live.com"]
p line_from_file.scan(regex) # => []