Ruby - Using multiple conditions on a single line - ruby

So, I'm running into this issue wherein I want to have three conditions be checked before the routine continues, but it keeps throwing up syntax errors saying it didn't expect the multiple conditions. Now, I know I've seen other people use lines such as:
if x > 100 && x % 2 == 1
#Do something
end
But, for whatever reason, this line:
if (letters.eql? letters.upcase && dash.eql? '-' && numbers.to_i.to_s.eql? numbers)
is throwing up tons of errors. Is it something to do with '.eql?' or is it something extraneous about Ruby that I haven't encountered yet?
Here's the rest of the code for reference:
print "Enter license plate: ";
input = gets.strip;
if input.length == 8
letters = input[0,2];
dash = input[3];
numbers = input[4,7];
if (letters.eql? letters.upcase && dash.eql? '-' && numbers.to_i.to_s.eql? numbers)
puts "#{input} is a valid license plate."
else
print "All valid license plates are three (3) uppercase letters, followed by a dash (-), followed by four (4) digits";
end
else
print "All valid license plates are 8 characters long.";
end
Also, these are the errors:
LicensePlate.rb:7: syntax error, unexpected tSTRING_BEG, expecting ')'
...? letters.upcase && dash.eql? '-' && numbers.to_i.to_s.eql? ...
... ^
LicensePlate.rb:7: syntax error, unexpected tIDENTIFIER, expecting ')'
... numbers.to_i.to_s.eql? numbers)
...

This should do it:
if letters.eql?(letters.upcase) && dash.eql?('-') && numbers.to_i.to_s.eql?(numbers)
You can still wrap the entire conditional in parenthesis if you would like, but with Ruby (unlike JavaScript), you don't need to.

Think you're just missing some parens - try this:
if (letters.eql?(letters.upcase) && dash.eql?('-') && numbers.to_i.to_s.eql?(numbers))

This also works:
letters.eql? letters.upcase and dash.eql? '-' and numbers.to_i.to_s.eql? numbers
I believe this is due to operator precedence since this also works:
(letters.eql? letters.upcase) && (dash.eql? '-') && (numbers.to_i.to_s.eql? numbers)
Ruby seem to try and evaluate your condition prematurely.
EDIT: Just saw that Lurker was mentioning precedence previously.

In addition to the other answers - consider using a regular expression to check the format:
print "Enter license plate: "
input = gets.chomp
if input.length != 8
puts "All valid license plates are 8 characters long."
elsif input !~ /^[A-Z]{3}-\d{4}$/
print "All valid license plates are three (3) uppercase letters, followed by a dash (-), followed by four (4) digits"
else
puts "#{input} is a valid license plate."
end

Related

Convert leading spaces to tabs in ruby

Given the following indented text:
two spaces
four
six
non-leading spaces
I'd like to convert every 2 leading spaces to a tab, essentially converting from soft tabs to hard tabs. I'm looking for the following result (using an 'x' instead of "\t"):
xtwo spaces
xxfour
xxxsix
non-leading spaces
What is the most efficient or eloquent way to do this in ruby?
What I have so far seems to be working, but it doesn't feel right.
input.gsub!(/^ {2}/,"x")
res = []
input.split(/\n/).each do |line|
while line =~ /^x+ {2}/
line.gsub!(/^(x+) {2}/,"\\1x")
end
res << line
end
puts res.join("\n")
I noticed the answer using sed and \G:
perl -pe '1 while s/\G {2}/\t/gc' input.txt >output.txt
But I can't figure out how to mimic the pattern in Ruby. This is as far as I got:
rep = 1
while input =~ /^x* {2}/ && rep < 10
input.gsub!(/\G {2}/,"x")
rep += 1
end
puts input
Whats wrong with using (?:^ {2})|\G {2} in multi-line mode?
The first match will always be at the beginning of the line,
then \G will match succesively right next to that, or the match
will fail. The next match will always be the beginning of the line.. repeats.
In Perl its $str =~ s/(?:^ {2})|\G {2}/x/mg; or $str =~ s/(?:^ {2})|\G {2}/\t/mg;
Ruby http://ideone.com/oZ4Os
input.gsub!(/(?:^ {2})|\G {2}/m,"x")
Edit: Of course the anchors can be factored out and put into an alternation
http://ideone.com/1oDOJ
input.gsub!(/(?:^|\G) {2}/m,"x")
You can just use a single gsub for that:
str.gsub(/^( {2})+/) { |spaces| "\t" * (spaces.length / 2) }

Checking if a string has balanced parentheses

I am currently working on a Ruby Problem quiz but I'm not sure if my solution is right. After running the check, it shows that the compilation was successful but i'm just worried it is not the right answer.
The problem:
A string S consisting only of characters '(' and ')' is called properly nested if:
S is empty,
S has the form "(U)" where
U is a properly nested string,
S has
the form "VW" where V and W are
properly nested strings.
For example, "(()(())())" is properly nested and "())" isn't.
Write a function
def nesting(s)
that given a string S returns 1 if S
is properly nested and 0 otherwise.
Assume that the length of S does not
exceed 1,000,000. Assume that S
consists only of characters '(' and
')'.
For example, given S = "(()(())())"
the function should return 1 and given
S = "())" the function should return
0, as explained above.
Solution:
def nesting ( s )
# write your code here
if s == '(()(())())' && s.length <= 1000000
return 1
elsif s == ' ' && s.length <= 1000000
return 1
elsif
s == '())'
return 0
end
end
Here are descriptions of two algorithms that should accomplish the goal. I'll leave it as an exercise to the reader to turn them into code (unless you explicitly ask for a code solution):
Start with a variable set to 0 and loop through each character in the string: when you see a '(', add one to the variable; when you see a ')', subtract one from the variable. If the variable ever goes negative, you have seen too many ')' and can return 0 immediately. If you finish looping through the characters and the variable is not exactly 0, then you had too many '(' and should return 0.
Remove every occurrence of '()' in the string (replace with ''). Keep doing this until you find that nothing has been replaced (check the return value of gsub!). If the string is empty, the parentheses were matched. If the string is not empty, it was mismatched.
You're not supposed to just enumerate the given examples. You're supposed to solve the problem generally. You're also not supposed to check that the length is below 1000000, you're allowed to assume that.
The most straight forward solution to this problem is to iterate through the string and keep track of how many parentheses are open right now. If you ever see a closing parenthesis when no parentheses are currently open, the string is not well-balanced. If any parentheses are still open when you reach the end, the string is not well-balanced. Otherwise it is.
Alternatively you could also turn the specification directly into a regex pattern using the recursive regex feature of ruby 1.9 if you were so inclined.
My algorithm would use stacks for this purpose. Stacks are meant for solving such problems
Algorithm
Define a hash which holds the list of balanced brackets for
instance {"(" => ")", "{" => "}", and so on...}
Declare a stack (in our case, array) i.e. brackets = []
Loop through the string using each_char and compare each character with keys of the hash and push it to the brackets
Within the same loop compare it with the values of the hash and pop the character from brackets
In the end, if the brackets stack is empty, the brackets are balanced.
def brackets_balanced?(string)
return false if string.length < 2
brackets_hash = {"(" => ")", "{" => "}", "[" => "]"}
brackets = []
string.each_char do |x|
brackets.push(x) if brackets_hash.keys.include?(x)
brackets.pop if brackets_hash.values.include?(x)
end
return brackets.empty?
end
You can solve this problem theoretically. By using a grammar like this:
S ← LSR | LR
L ← (
R ← )
The grammar should be easily solvable by recursive algorithm.
That would be the most elegant solution. Otherwise as already mentioned here count the open parentheses.
Here's a neat way to do it using inject:
class String
def valid_parentheses?
valid = true
self.gsub(/[^\(\)]/, '').split('').inject(0) do |counter, parenthesis|
counter += (parenthesis == '(' ? 1 : -1)
valid = false if counter < 0
counter
end.zero? && valid
end
end
> "(a+b)".valid_parentheses? # => true
> "(a+b)(".valid_parentheses? # => false
> "(a+b))".valid_parentheses? # => false
> "(a+b))(".valid_parentheses? # => false
You're right to be worried; I think you've got the very wrong end of the stick, and you're solving the problem too literally (the info that the string doesn't exceed 1,000,000 characters is just to stop people worrying about how slow their code would run if the length was 100times that, and the examples are just that - examples - not the definitive list of strings you can expect to receive)
I'm not going to do your homework for you (by writing the code), but will give you a pointer to a solution that occurs to me:
The string is correctly nested if every left bracket has a right-bracket to the right of it, or a correctly nested set of brackets between them. So how about a recursive function, or a loop, that removes the string matches "()". When you run out of matches, what are you left with? Nothing? That was a properly nested string then. Something else (like ')' or ')(', etc) would mean it was not correctly nested in the first place.
Define method:
def check_nesting str
pattern = /\(\)/
while str =~ pattern do
str = str.gsub pattern, ''
end
str.length == 0
end
And test it:
>ruby nest.rb (()(())())
true
>ruby nest.rb (()
false
>ruby nest.rb ((((()))))
true
>ruby nest.rb (()
false
>ruby nest.rb (()(((())))())
true
>ruby nest.rb (()(((())))()
false
Your solution only returns the correct answer for the strings "(()(())())" and "())". You surely need a solution that works for any string!
As a start, how about counting the number of occurrences of ( and ), and seeing if they are equal?

ruby regex matching cent ¢

I am having difficulty matching string "79¢ /lb" with this regex: (\$|¢)\d+(.\d{1,2})?
It works fine when the cent symbol appears in the beginning, but I don't know what needs to be added near the end of the string.
Basically I'm planning to extract a float value from this price tag, that is, 0.79, thanks in advance, I'm using ruby.
Well, that regex requires the $ or ¢ to be at the start of the string. To match 79¢ /lb, you'll need something like:
(\d+)¢
where the ¢ comes after the digits.
A single regex to match the many varied formats that you're likely to see will be a little more complex. I would suggest either doing it as multiple regexes (for simplicity), or asking another question here specifying the full range of strings you want to capture the prices from.
It's easiest to figure out the right regex when you consider each case separately. If I understand your question correctly, there are 4 cases:
cents, with the ¢ symbol before the price
cents, with the ¢ symbol after the price
dollars (and optional cents), with the $ symbol before the price
dollars (and optional cents), with the $ symbol after the price
First, write a regex for each case separately:
¢(\d{1,2})\b
\b(\d{1,2})¢
\$(\d+(?:\.\d{2})?)\b
\b(\d+(?:\.\d{2})?)\$
Then, combine them into a single regex:
regex = %r{
¢(\d{1,2})\b | # case 1
\b(\d{1,2})¢ | # case 2
\$(\d+(?:\.\d{2})?)\b | # case 3
\b(\d+(?:\.\d{2})?)\$ # case 4
}x
Then, match to your heart's content:
string_with_prices.scan(regex) do |match|
# If there was a match in the first two groups, it's for cents
cents = $1 || $2
# ...and the last two groups are dollars.
dollars = $3 || $4
if cents
puts "found price (cents): #{cents}"
elsif dollars
puts "found price (dollars): #{dollars}"
else
puts 'unknown match!'
end
end
Note: To test this code, I had to use 'c' instead of '¢' because Ruby was telling me invalid multibyte char (US-ASCII). To avoid this issue, use a different character encoding, or else figure out the encoded value of the '¢' character and embed it directly in the regex, e.g. %r{\x42} instead of %r{¢}.
Maybe you don't need to do everything in your reg exp;
#price is the string that contains the price
if price =~ /\$|¢/
value = string.match(/\d+/)
end
Or something along those lines.

Remove whitespace, but do so last?

I am attempting to parse Lua, which depends on whitespace in some cases due to the fact that it doesn't use braces for scope. I figure that by throwing out whitespace only if another rule doesn't match is the best way, but i have no clue how to do that. Can someone help me?
Looking at Lua's documentation, I see no need to take spaces into account.
The parser rule ifStatement:
ifStatement
: 'if' exp 'then' block ('elseif' exp 'then' block 'else' block)? 'end'
;
exp
: /* todo */
;
block
: /* todo */
;
should match both:
if j==10 then print ("j equals 10") end
and:
if j<10 then
print ("j < 10")
elseif j>100 then
print ("j > 100")
else
print ("j >= 10 && j <= 100")
end
No need to take spaces into account, AFAIK. So you can just add:
Space
: (' ' | '\t' | '\r' | '\n'){$channel=HIDDEN;}
;
in your grammar.
EDIT
It seems there is a Lua grammar on the ANTLR wiki: http://www.antlr.org/grammar/1178608849736/Lua.g
And it seems I my suggestion for an if statement slightly differs from the grammar above:
'if' exp 'then' block ('elseif' exp 'then' block)* ('else' block)? 'end'
which is the correct one, as you can see.

Ruby: String Comparison Issues

I'm currently learning Ruby, and am enjoying most everything except a small string comparason issue.
answer = gets()
if (answer == "M")
print("Please enter how many numbers you'd like to multiply: ")
elsif (answer. == "A")
print("Please enter how many numbers you'd like to sum: ")
else
print("Invalid answer.")
print("\n")
return 0
end
What I'm doing is I'm using gets() to test whether the user wants to multiply their input or add it (I've tested both functions; they work), which I later get with some more input functions and float translations (which also work).
What happens is that I enter A and I get "Invalid answer."The same happens with M.
What is happening here? (I've also used .eql? (sp), that returns bubcus as well)
gets returns the entire string entered, including the newline, so when they type "M" and press enter the string you get back is "M\n". To get rid of the trailing newline, use String#chomp, i.e replace your first line with answer = gets.chomp.
The issue is that Ruby is including the carriage return in the value.
Change your first line to:
answer = gets().strip
And your script will run as expected.
Also, you should use puts instead of two print statements as puts auto adds the newline character.
your answer is getting returned with a carriage return appended. So input "A" is never equal to "A", but "A(return)"
You can see this if you change your reject line to print("Invalid answer.[#{answer}]"). You could also change your comparison to if (answer.chomp == ..)
I've never used gets put I think if you hit enter your variable answer will probably contain the '\n' try calling .chomp to remove it.
Add a newline when you check your answer...
answer == "M\n"
answer == "A\n"
Or chomp your string first: answer = gets.chomp

Resources