I am VERY new to Ruby. I was trying to make a simple "How's your day?" kind of thing, but when I answer with "Good" it's supposed to return "Good to hear" but it skips it and goes to my else statement that returns "Not valid". Same thing when I enter "Bad", it's supposed to give me "Oh no" but instead it gives me "Not valid". I know your usually supposed to use ==, but I don't know what I am missing here. Thank you for your help.
puts "How are you?"
answer = gets
if (answer == "Good");
print("Good to hear")
elsif (answer == "Bad");
print("Oh no")
else;
print("Not valid")
end
gets will capture a string including an endline character (\n). You're comparing the string Good (for example) against Good\n, and it obviously doesn't match.
You can observe this by adding a line after you populate answer, like puts answer.inspect (or more tersely, p answer). This will show you the string along with any not-normally-visible characters.
The easiest way to fix this will be to use answer = gets.strip, which will remove whitespace characters (including spaces, tabs, and newlines) from end of the captured input string.
Related
So as I ask for in the title. How do I make a loop that breaks when the user has entered some values that contain only number, and if not it will say try again.
prompt = "> "
puts "What is the salary for the accountant: "
print prompt
while accountant = gets.chomp
if accountant == (0..9)
puts "Nice"
break
else
"try again"
print prompt
end
end
end
A simple solution with no regex would be:
accountant.chars.all?{|n| ("0".."9") === n}
You may want to read about the "===" operator in Ruby if you don't how it works yet as it may be confusing if you come from PHP or Javascript.
What does the "===" operator do in Ruby?
Your problem is in this line:
if accountant == (0..9)
This is checking whether the value is equal to a range - which is not what you wanted.
Since the input from gets.chomp will always be a string, you need to check whether it only contains the characters: "0", "1", "2", ... and "9".
One way to do this is with a regular expression:
if accountant =~ /\A\d+\z/
\A means "start of string"
\z means "end of string"
\d+ means "one or more digit" (0-9)
Note that the solution you suggested in the comments, /^-?[0-9]+$/, is flawed since:
^ means "start of line" (so it would be possible to insert arbitrary other characters before a newline)
$ means "end of line" (so it would be possible to insert arbitrary other characters after a newline)
-? also allows an optional hyphen character. Which is presumably not what you want in this context, since the input is a salary - which surely cannot be negative!
I wrote the following code:
print "Please enter a string"
user_input = gets.chomp
user_input.downcase!
if user_input.include? "s"
print "Changing #{user_input} to #{user_input.gsub!(/s/,'th')}"
else
print "No s in the string"
end
and I found that user_input and user_input.gsub!(/s/,'th') contain the same value. This happens because of the bang operation on gsub and because they are part of the same string.
Splitting the print in two lines changes the behavior:
print "Changing #{user_input} to "
print "#{user_input.gsub!(/s/,'th')}"
I wonder if this is a bug.
It's a feature, not a bug.
String interpolation (the "#{}" operator) works by finding all the dynamic parts, evaluating them and then glueing static and dynamic parts together into one string. Since all dynamic parts are evaluated prior to concatenation, gsub! mutates the object which user_input points to. So the first appearance of inner_page in that string will see the updated value.
Solution: don't use dangerous gsub!, use safe gsub.
You can observe here, how it really happens (VM instructions). This will probably be Chinese to you at the moment, but in a few years you'll understand. :)
code = <<-RUBY
user_input = 'blah'
print "Changing \#{user_input} to \#{user_input.gsub!(/s/,'th')}"
RUBY
puts RubyVM::InstructionSequence.new(code).disasm
I am trying to write a method that takes in a string that will have no spaces. All I want it to do is to return "bug" when the character in the string is a letter [A-Za-z] and to return "ant" if it's any other character.
def Letter(str)
(0..str.length).to_a do |index|
if str[index].chr =~ /[A-Za-z]/ ##I think this is where things are going wrong.
puts "bug"
else
puts "ant"
end
end
end
Does anyone have any idea how to fix this? I keep getting arrays of consecutive numbers.
Rewritten
def letter(str)
str.each_char.map do |char|
(char =~ /[[:alpha:]]/) ? 'bug' : 'ant'
end
end
In your code, you are trying to print "bug" or "ant"; but you're returning (0..str.length).to_a. This function will return an array of bugs and ants. It is also made more Rubyish:
methods should be in snake_case (lowercase, with underscores between words)
iterating over strings is easier with each_char
it's fine with [A-Za-z], but [[:alpha:]] is both clearer and handles Unicode stuff.
since we're testing each character, you know it's going to be one character long, so you don't need the start of line and end of line anchors.
def letter(str)
str.chars.each do |x|
puts x=~ /[A-Za-z]/ ? "bug" : "ant"
end
end
First things first, in your loop your are trying to convert a range
into an array.
(0..str.length).to_a
str.length returns a number, therefore making it into an array will give you an array of numbers. Hence your problem.
Second, you have to have brackets around your /a-zA-Z/ regex
Third, use the ternary operator. It's great for small if statements. Heres the syntax:
boolean ? "if boolean is true this code will execute" : "else this code will"
Fourth, use the .each methods, ruby is loved partly because of the simplicity of loops and iterating!
Happy coding!
I want to get the first letter of each word put together, making something like "I need help" turn into "Inh". I was thinking to trim everything off, then going from there, or grab each first letter right away.
You could simply use split, map and join together here.
string = 'I need help'
result = string.split.map(&:first).join
puts result #=> "Inh"
How about regular expressions? Using the split method here forces a focus on the parts of the string that you don't need to for this problem, then taking another step of extracting the first letter of each word (chr). that's why I think regular expressions is better for this case. Node that this will also work if you have a - or another special character in the string. And then, of course you can add .upcase method at the end to get a proper acronym.
string = 'something - something and something else'
string.scan(/\b\w/).join
#=> ssase
Alternative solution using regex
string = 'I need help'
result = string.scan(/(\A\w|(?<=\s)\w)/).flatten.join
puts result
This basically says "look for either the first letter or any letter directly preceded by a space". The scan function returns array of arrays of matches, which is flattened (made into one array) and joined (made into a string).
string = 'I need help'
result = string.split.map(&:chr).join
puts result
http://ruby-doc.org/core-2.0/String.html#method-i-chr
Let us imagine, that we have a simple abstract input form, whose aim is accepting some string, which could consist of any characters.
string = "mystical characters"
We need to process this string by making first character uppercased. Yes, that is our main goal. Thereafter we need to display this converted string in some abstract view template. So, the question is: do we really need to check whether the first character is already written correctly (uppercased) or we are able to write just this?
theresult = string.capitalize
=> "Mystical characters"
Which approach is better: check and then capitalize (if need) or force capitalization?
Check first if you need to process something, because String#capitalize doesn't only convert the first character to uppercase, but it also converts all other characters downcase. So..
"First Lastname".capitalize == "First lastname"
That might not be the wanted result.
If I understood correctly you are going to capitalize the string anyway, so why bother checking if it's already capitalized?
Based on Tonttu answer I would suggest not to worry too much and just capitalize like this:
new_string = string[0...1].capitalize + string[1..-1]
I ran in to Tonttu's problem importing a bunch of names, I went with:
strs = "first lastname".split(" ")
return_string = ""
strs.each do |str|
return_string += "#{str[0].upcase}#{str[1..str.length].downcase} "
end
return_string.chop
EDIT: The inevitable refactor (over a year) later.
"first lastname".split(" ").map do |str|
"#{str[0].upcase}#{str[1..str.length].downcase}"
end.join(' ')
while definitely not easier to read, it gets the same result while declaring fewer temporary variables.
I guess you could write something like:
string.capitalize unless string =~ /^[A-Z].*/
Personally I would just do string.capitalize
Unless you have a flag to be set for capitalized strings which you going to check than just capitalize without checking.
Also the capitalization itself is probably performing some checking.