Ruby, greater than with variable above 1000 not working - ruby

here is my code
print("How far in metres are the people away from the spacecraft?")
people = gets.chomp
if people > "600" and (people !~ /\D/)
print ""
else
while !(people > "600" and (people !~ /\D/))
if people < "600" then
print"The people are too close to the launch site, make sure they are 600 metres away from it."
print "How far in metres are the people away from the spacecraft?"
people = gets.chomp
end
if !(people !~ /\D/)
puts "only enter numbers not letters. Please try again:"
people = gets.chomp
end
end
end
print ("The people are away from the launch site.")
I want the last line to appear when 'people' is above 600 but it also has to be a number. but the last line only appears if "people" is below 1000 above 600. Thanks for all the help.
There are images below
1000
789

The problem is that you're comparing Strings instead of Integers.
The strings are being compared alphabetically, so "1000" < "700" will be true, because "1000" appears before "700" when sorted alphabetically.
What you want is to convert the strings into integers before comparing them. Something like this:
people = "700"
if people.to_i > 600
puts "It's greater than 600"
else
puts "It's less than 600"
end
Notice the lack of quotes around 600.

Cast as Integer
When you want to compare integers as numerical values, you need to convert the string stored in people first. Most people will tell you to use String#to_i, but that can be problematic and lead to excessive error-checking code. It's better to use Kernel#Integer, which not only performs the cast but also raises an exception of the string can't be coerced. For example:
print 'Get integer: '
# Remove newlines and thousands separators, then cast as an integer.
people = Integer gets.chomp.delete ','
if people >= 600
puts 'Far enough.'
else
puts 'Not far enough.'
end
This way, if you enter a value such as one thousand or x1000x you'll get an exception like:
ArgumentError: invalid value for Integer(): "x1000x"

Related

How do I check if user input is an integer in Ruby?

I am trying to loop until user inputs an integer. When user inputs a letter, the following code should print "Think of a number":
print "Think of a number "
while user_input = gets.to_i
if user_input.is_a? Integer
puts "your number is #{user_input}"
break
else
print "Think of a number "
end
end
I succeeded with my code when user inputs an integer. However when user inputs a string, the to_i method returns 0, and does not execute the else statement because it is a number.
The main issue with your code is String#to_i method is omnivorous.
"0".to_i #⇒ 0
"0.1".to_i #⇒ 0
"foo".to_i #⇒ 0
That said, user_input in your code is always integer.
What you probably want is to accept digits only (and maybe a leading minus for negatives.) The only concise way to accept a subset of characters is a regular expression.
# chomp to strip out trailing carriage return
user_input = gets.chomp
if user_input =~ /\A-?\d+\z/
...
The regular expression above means nothing save for digits with optional leading minus.
Or, even better (credits to #Stefan)
if gets =~ /\A-?\d+\Z/
If you only want to accept postive digits, you can use a range:
user_input = gets.chomp
if ('0'..'9').cover? user_input
let check below one used Integer(gets.chomp) rescue ''
print "Think of a number "
while user_input = Integer(gets.chomp) rescue ''
if user_input.is_a? Integer
puts "your number is #{user_input}"
break
else
print "Think of a number "
end
end
I came across a similar problem. I ended up doing this:
if user_input.strip == user_input.to_i.to_s
# More code here!
end
Testing for float would be:
if user_input.strip == user_input.to_f.to_s
# More code here!
end
Solved my issue. See if it helps.

find instances of regex, transform into integers, do math and replace in the same place?

I have a long string input that contains Taiwanese dates. I need to transform them into American notation and leave them in the same exact place of the input. I have created regex that do match against the text in the input but I cannot find the way to transform those matches into integers, do math (to change the year) and then replace the new values in the exact same place where the old values were.
Taiwanese dates are formed as yyy/mm/dd.
For ex: 107年02月13日, that is 02/13/2018
Up to now I have:
input = gets
texto = input.gsub(/\s+/, "")
Date_with_characters = /\d{3}年\d{2}月\d{2}日/
if input.match(Date_with_characters)
puts "Encuentro fechas con caracteres"
elsif
puts "NO encuentro un joraca con caracteres"
end
Date_with_slashes = %r{\d{3}/\d{2}/\d{2}}
if input.match(Date_with_slashes)
puts "Encuentro fechas con barras"
elsif
puts "NO encuentro un joraca con barras"
end
The code above finds all dates (both with characters and slashes) but I was hoping I could then turn the first 3 indexes in the year to integers, do the math to turn it into western calendar, and put it back in the same place (skipping moving year to the end for now). I have had no luck yet and I tried lot of things.
Thanks a lot!
You can put the numbers in parentheses to capture their values separately and use gsub with a block to perform a dynamic substitution:
str = 'foo 107年02月13日 bar'
str.gsub(/(\d{3})年(\d{2})月(\d{2})日/) { "#{$2}/#{$3}/#{$1.to_i + 1911}" }
#=> "foo 02/13/2018 bar"
Within the block, the special variables $1, $2 and $3 refer to the text matched by the corresponding capture group, i.e. "107", "02" and "13" respectively. The block's result becomes the new value for the matched text.
There's also gsub! (with a !) which performs the substitution in-place (i.e. it modifies the receiver), returning nil if no matches were found. This can be useful if you want to provide a message depending on whether a replacement occured:
if input.gsub!(/(\d{3})年(\d{2})月(\d{2})日/) { "#{$2}/#{$3}/#{$1.to_i + 1911}" }
puts 'dates have been converted'
else
puts 'no dates could be found'
end
This is a way to do it that also confirms that dates are valid. The latter is essentially a freebie with the approach that I have taken.
require 'date'
def convert_date(str)
str.gsub(/\d{3}年\d{2}月\d{2}日/) do |s|
dt = DateTime.strptime(s, '%Y年%m月%d日') rescue nil
(raise ArgumentError, "#{s} is not a valid date") if dt.nil?
"#{dt.month}/#{dt.day}/#{dt.year.to_i + 1911}"
end
end
convert_date 'foo 107年02月13日 bar and 106年11月25日 baz'
#=> "foo 2/13/2018 bar and 11/25/2017 baz"
convert_date 'foo 107年02月13日 bar and 106年02月29日 baz'
#=> ArgumentError (106年02月29日 is not a valid date)
See DateTime::strptime and Kernel#raise.

So I want the answer for the user just to include numbers from 0 to 9.. How do I do this?

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!

Basic Ruby gets.chomp

I'm new to programming and I'm trying to answer this basic question.
Write a program which asks for a person's favorite number. Have your program add one to the number, then suggest the result as a bigger and better favorite number.
This is what I have to far, but it won't convert to a number.
puts "What is your favorite number?"
number = gets.chomp
number = number.to_i + 1
puts "I suggest " + number + " as a bigger and better number"
Look more closely at the error you get:
What is your favorite number?
42
number.rb:4:in `+': can't convert Fixnum into String (TypeError)
from number.rb:4:in `<main>'
Line 4 is:
puts "I suggest " + number + " as a bigger and better number"
The problem is that Ruby won't implicitly convert number into a string (e.g. "foo" + 42 is not valid in Ruby). There are a couple of solutions:
Call to_s on number to convert it to a string before concatenating:
puts "I suggest " + number.to_s + " as a bigger and better number"
Use Ruby string interpolation:
puts "I suggest #{number} as a bigger and better number"
Option 2 is more idiomatic, I suggest using that.
As in many other problems in ruby there are a lot of ways to do it....without the three solutions writed above there is two more:
puts "What is your favorite number?"
number = gets.chomp.to_i
puts "I suggest %d as a bigger and better number" % [number + 1]
and one wich is almost the same:
puts "What is your favorite number?"
number = gets.chomp.to_i
num = number + 1
puts "I suggest %d as a bigger and better number" % [num]
You can do it this way:
print 'What is your favorite number? '
number = gets.chomp
puts "I suggest #{number.to_i + 1} as a bigger and better number"
There is not to much to explain about the code, but there are few things to take into account:
If you are rendering plain text use 'text' instead of "text". "In the double-quoted case, Ruby does more work. First, it looks for substitutions (sequences
that start with a backslash character) and replaces them with some binary value" - Programming ruby 1.9.3
Always try to reduce the number of lines of code.
This things are really insignificant here, but when you are coding a big program, web page etc., it really makes a difference.

Format output to 40 characters long per line

I'm fairly new to Ruby and I've been searching Google for a few hours now.
Does anyone know how to format the output of a print to be no more than 40 characters long?
For example:
What I want to print:
This is a simple sentence.
This simple
sentence appears
on four lines.
But I want it formatted as:
This is a simple sentence. This simple
sentence appears on four lines.
I have each line of the original put into an array.
so x = ["This is a simple sentence.", "This simple", "sentence appears", "on three lines."]
I tried x.each { |n| print n[0..40], " " } but it didn't seem to do anything.
Any help would be fantastic!
The method word_wrap expects a Strind and makes a kind of pretty print.
Your array is converted to a string with join("\n")
The code:
def word_wrap(text, line_width = 40 )
return text if line_width <= 0
text.gsub(/\n/, ' ').gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip
end
x = ["This is a simple sentence.", "This simple", "sentence appears", "on three lines."]
puts word_wrap(x.join("\n"))
x << 'a' * 50 #To show what happens with long words
x << 'end'
puts word_wrap(x.join("\n"))
Code explanation:
x.join("\n")) build a string, then build one long line with text.gsub(/\n/, ' ').
In this special case this two steps could be merged: x.join(" "))
And now the magic happens with
gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n")
(.{1,#{line_width}})): Take any character up to line_width characters.
(\s+|$): The next character must be a space or line end (in other words: the previous match may be shorter the line_width if the last character is no space.
"\\1\n": Take the up to 40 character long string and finish it with a newline.
gsub repeat the wrapping until it is finished.
And in the end, I delete leading and trailing spaces with strip
I added also a long word (50 a's). What happens? The gsub does not match, the word keeps as it is.
puts x.join(" ").scan(/(.{1,40})(?:\s|$)/m)
This is a simple sentence. This simple
sentence appears on three lines.
Ruby 1.9 (and not overly efficient):
>> x.join(" ").each_char.each_slice(40).to_a.map(&:join)
=> ["This is a simple sentence. This simple s", "entence appears on three lines."]
The reason your solution doesn't work is that all the individual strings are shorter than 40 characters, so n[0..40] always is the entire string.

Resources