The pig latin translation - ruby

I am trying to solve the "pig latin problem" in the Test-First Ruby lessons.
In this program I am basically trying to translate a string with the following rules:
If a word begins with a vowel sound, add an "ay" sound to the end of the word.
If a word begins with a consonant sound, move it to the end of the word, and then add an "ay" sound to the end of the word.
For this I wrote the following code which worked fine:
def translate(word)
words=word.split(" ")
words.each do |x|
if ["a","e","i","o","u"].include?x[0,1]
x << ("ay")
else
x << ("#{x[0,1]}ay")
x[0,1]=""
end
end
words.join(" ")
end
However, the problem also states that when translating words with 2, or 3 consonants in the beginning, it should move them all at the end of the word, and then add "ay".
For that I ended an until loop into the else statement:
def translate(word)
words=word.split(" ")
words.each do |x|
if ["a","e","i","o","u"].include?x[0,1]
x << ("ay")
else
until ["a","e","i","o","u"].include?x[0,1]
x << ("#{x[0,1]}")
x[0,1]=""
end
x << ("#{x[0,1]}ay")
end
end
words.join(" ")
end
This is giving me this result:
translate("the bridge over the river kwai")
=> "etheay idgebriay overay etheay iverriay aikwaay"
So, it is running the until loop one extra time and adding the first vowel in the word to the end as well. However, it is not removing this vowel from the first position.
What am I doing wrong?

It's this line: x << ("#{x[0,1]}ay").
You've already shaved off the consonants from the beginning of the word so that it starts with a vowel, and then you're adding that vowel ("#{x[0,1]}") to the end along with the ay.
So, replace x << ("#{x[0,1]}ay") with just x << "ay" and it should work.

(NOTE: technically this is not an answer)
Your original code is not very idiomatic. You're running while loops and mutating strings in-place. You don't see that in good ruby code. May I offer you an improved version?
def vowel?(str)
["a","e","i","o","u"].include?(str)
end
def translate_word(word)
first_vowel_idx = word.chars.find_index{|c| vowel?(c)}
leading_consonants = word[0..first_vowel_idx-1]
rest_of_the_word = word[first_vowel_idx..-1]
rest_of_the_word + leading_consonants + 'ay'
end
def translate(sentence)
words = sentence.split(" ")
words.map{|w| translate_word(w) }.join(" ")
end
translate("the bridge over the river kwai") # => "ethay idgebray overoveray ethay iverray aikway"

Related

How to make my code interactive with ARGV in RUBY

This is my PigLatin code and it works well but I need make it interactive with ARGV, it should be:
$ ruby pig_latin.rb pig banana trash apple elephant
=> igpay ananabay ashtray appleway elephantway
def pig_latin(input)
first_char = input[0,1]
vowels = "aeiouAEIOU"
if vowels.include?(first_char)
word = input[1..-1] + first_char + "way"
else
word = input[1..-1] + first_char + "ay"
end
end
Add this at the end of the program:
if __FILE__ == $0 # if file is being run as script from command line
puts(ARGV.map { |string| pig_latin(string) }.join(" "))
end
ARGV is an array of strings. You can use map to apply the pig_latin changes, and then print them on the same line, joined by " "
The benefit of using if __FILE__ == $0 is that it doesn't require your program to use ARGV. E.g. you could still use it with require.
Here's a cleaned up version that's more Ruby-like:
def pig_latin(input)
case (first_char = input[0,1])
when /aeiou/i
# Uses a simple regular expression to detect vowels
input[1..-1] + first_char + "way"
else
input[1..-1] + first_char + "ay"
end
end
# Transform the input arguments into their Pig Latin equivalents
# and combine into a single string by joining with spaces.
piglatined = ARGV.map do |arg|
pig_latin(arg)
end.join(' ')
puts piglatined

Pig Latin exercise works, but only for one user inputed word. Not all words

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.

How do I join the final result so it is not an array, but a string?

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

How do I capitalize all words in a string apart from small words in the middle and in the beginning?

I have a long string, "the silver rider on his back and the palm tree". I would like to write a Ruby method that capitalizes all words except "on", "the", and "and" in the middle of the sentence, but have the "the" capitalized at the beginning?
Here is what I have so far:
def title(word)
small_words = %w[on the and]
word.split(' ').map do |w|
unless small_words.include?(w)
w.capitalize
else
w
end
end.join(' ')
end
This code actually does most of what I need but don't know how to include or exclude for that matter the "the" at the beginning of the sentence.
This will capitalize all the words, except for the stop words (your small words) that aren't the first in the sentence.
def title(sentence)
stop_words = %w{a an and the or for of nor} #there is no such thing as a definite list of stop words, so you may edit it according to your needs.
sentence.split.each_with_index.map{|word, index| stop_words.include?(word) && index > 0 ? word : word.capitalize }.join(" ")
end
It’s easiest to just forget about the special case of the first letter initially and then handle it after doing everything else:
def title(sentence)
small_words = %w[on the and]
capitalized_words = sentence.split(' ').map do |word|
small_words.include?(word) ? word : word.capitalize
end
capitalized_words.first.capitalize!
capitalized_words.join(' ')
end
This also capitalizes any “small word” at the beginning, not just “the”—but I think that’s probably what you want anyway.
A simple mod to your existing code would make it work:
def title( word )
small_words = %w[on the and]
word.split(' ').map.with_index do |w, i|
unless (small_words.include? w) and (i > 0)
w.capitalize
else
w
end
end.join(' ')
end
SmallWords = %w[on the and]
def title word
word.gsub(/[\w']+/){
SmallWords.include?($&) && $~.begin(0).zero?.! ? $& : $&.capitalize
}
end

Ruby: Pig Latin: Method to iterate through multiple words (not working)

Sorry, yet another question regarding the TestFirst.org Ruby exercise to write a 'Pig Latin' method, coming from a newbie. The other answers helped somewhat but I wasn't able to adapt them successfully. The main issue is that I'm trying to write a method to scan through a string of words (not just a single word), modify some of the words (if applicable), then return the full string back.
Below is my code attempting to perform the first part of the exercise, which is to append "ay" to any word beginning with a vowel. However, it is not working for me -- seems the .include? never returns true from comparing with a single letter(?)
Any help is much appreciated!
# PIG LATIN
# If any word within the input string begins with a vowel, add an "ay" to the end of the word
def translate(string)
vowels_array = %w{a e i o u y}
consonants_array = ('a'..'z').to_a - vowels_array
string_array = string.split
string_array.each do |word|
if vowels_array.include?(word[0])
word + 'ay'
end
end
return string_array.join(" ")
end
translate("apple orange mango") # => "appleay orangeay mango" but does not
string_array.each just iterates through string_array, doesn't change it; in order to update the contents of an array you should use map!:
# ...
string_array.map! do |word|
if vowels_array.include?(word[0])
word + 'ay'
else
word
end
end
# ...
translate("apple orange mango") #=> "appleay orangeay mango"
The purpose of else word end is to return the word also when the if condition is not satisfied.
Out of the array manipulating point of view, in most cases the best way to manipulate strings are regexps:
def translate(string)
string.gsub(/(^|\s)[aeiouy]\S*/i, '\0ay')
end
translate("apple orange mango") #=> "appleay orangeay mango"
Hash key lookup may be a bit faster
v= Hash['a', 1, 'o', '1', 'i', 1, 'u', 1, 'e', 1]
ws= %w(apple orange mango)
ws.map! do |w|
v[w[0]].nil? ? w : "#{w}ay"
end
p ws
Sounds like a job for a regular expression:
str = 'apple orange mango'
str.gsub(/\b[aeiou]\w*\b/, '\0ay')
#=> "appleay orangeay mango"
gsub will look for all occurences of a pattern (the first argument) and replace it with a string (the second argument). Inside that string, you can refer back to the matched pattern with \0 and append ay to it, which leaves us with \0ay.
Now the pattern (the actual regular expression) means “Capture whole words (\b matches word boundaries), that start with one of [aeiou] and end with zero ore more word characters (\w*)”.
So your complete method can be boiled down to:
def translate(string)
string.gsub /\b[aeiou]\w*\b/, '\0ay'
end
Et voilá!
Try:
def translate(string)
new_string = ''
string.split.each do |word|
if 'aoiue'.include?(word[0])
new_string += word + 'ay '
else
new_string += word + ' '
end
end
return new_string.strip
end
> translate("apple orange mango")
=> "appleay orangeay mango"

Resources