Bill Bisco Bill Bisco - 28 days ago 8
Ruby Question

Ruby: Trying to Match / character

I'm trying to use the .match to recognize a single / (forward slash) character.

The line in question that is currently not working is:

elsif i.match([/[/]/]) then


Any help would be appreciated. I have tried mixing in \ (backward slash) but to no avail so far.

def calc(input)
stack = []
array1 = input.split(//) #// splits into individual characters
array1.each do |i|
if i.match(/[0-9]/) then
stack.push(i.to_i)
puts "\n" ; print stack
#array1.slice!(i.to_i)
#array1.shift
#array1.delete_at(i.to_i)
#array1.delete(i)
elsif i.match(/[+]/) then
result = stack[-2] + stack[-1]
stack.pop
stack.pop
stack.push(result)
puts "\n" ; print stack
#puts "\n" ; print array1
elsif i.match(/[-]/) then
result = stack[-2] - stack[-1]
stack.pop
stack.pop
stack.push(result)
puts "\n" ; print stack
elsif i.match(/[*]/) then
result = stack[-2] * stack[-1]
stack.pop
stack.pop
stack.push(result)
puts "\n" ; print stack
elsif i.match([/[/]/]) then
result = stack[-2].to_f / stack[-1].to_f
stack.pop
stack.pop
stack.push(result)
puts "\n" ; print stack
end
end
end

Answer Source

Since you're breaking out your input into individual characters it's not necessary to use a regular expression to compare things. You can do straight-up comparisons like x == '/'. Given how many comparisons you're doing here, and they're all of a similar form, the structure you're actually looking for is to use a case statement:

def calc(input)
  stack = [ ]
  # Process individual characters in the string using `chars`
  input.chars.each do |c|
    case (c)
    when /[0-9]/
      stack << c.to_i
    when '+'
      a, b = stack.pop(2)
      stack << a + b
    when '-'
      a, b = stack.pop(2)
      stack << a - b
    when '*'
      a, b = stack.pop(2)
      stack << a * b
    when '/'
      a, b = stack.pop(2)
      stack << a / b
    end
  end

Note that Ruby's pop method takes an optional argument for how many you want to pop. In your case you want two, so you can just ask for that.

Now you get this:

calc('23+4*')
# => 20
calc('82/')
# => 4

Now there's a lot of repetition in this code, so it can be boiled down to even less if you embrace Ruby's dynamic programming possibilities:

def calc(input)
  stack = [ ]
  input.chars.each do |c|
    case (c)
    when /[0-9]/
      stack << c.to_i
    when '+', '-', '*', '/'
      # Combine the last two entries using the method named by
      # the character.
      stack << stack.pop(2).reduce(c)
    end
  end

  stack[0]
end

In Ruby a.send(:+, b) is the same as a+b so you can often use tools like reduce to apply an arbitrary operation on a set of things.