Ruby infix to postfix math expression converter (to RPN)

77 Views Asked by At

First of all, I started learning Ruby only 2 weeks ago, so please do not judge too harshly.

I wrote a script that does not work correctly with mathematical expressions containing parentheses. The script was written with reference to the RPN algorithm that I found on Wikipedia (some parts were simplified because my task was to write a small and relatively simple script).

Wiki algorithm:

  • While there are still characters to read:
    • Read the next character.
    • If the character is a number or a postfix function (e.g. ! - factorial), add it to the output string.
    • If the symbol is a prefix function (e.g., sin - sine), place it on the stack.
    • If the symbol is an opening parenthesis, place it on the stack.
    • If the symbol is a closing parenthesis: As long as the top element of the stack is not an opening parenthesis, push the elements off the stack into the output string. This removes the opening bracket from the stack, but does not add it to the output string. If the stack ends before we encounter the opening parenthesis, it means that either the delimiter is incorrect or the parentheses are not matched.
      • If there are different kinds of parentheses, the appearance of an unpaired parenthesis also indicates an error. If some brackets are functions at the same time (for example, [x] is an integer part), add the symbol of this function to the output string.
    • If the symbol is a binary operation o1, then:
      1. as long as the prefix function on the top of the stack is... ... OR the operation on the top of the stack is prioritized or of the same priority level as o1 ... OR the operation on the top of the stack is left-associative with the same priority as o1 ... push the top element of the stack to the output line;
      2. place the o1 operation on the stack.
  • When the input string is over, push all characters from the stack into the output string. Only the operation characters should have remained on the stack; if not, the expression has misaligned parentheses.

Ruby script:

    priorities = { "+" => 1, "-" => 1, "*" => 2, "/" => 2, "^" => 3 }
    output, stack = [], []
    
    input = gets.chop.to_s
    
    input.split.each do |smb|
      if smb.match?(/[[:digit:]]/)
        output << smb
      elsif smb == "("
        stack << smb
      elsif smb == ")"
        while stack.last != "("
          output << stack.pop
        end
        stack.pop
      else
        while !stack.empty? && priorities[smb] <= priorities[stack.last]
          output << stack.pop
        end
        stack << smb
      end
    end
    
    until stack.empty?
      output << stack.pop
    end
    
    puts output.join(' ')

Input: 3 ^ 2 + 5 / (2 + 1)

Output: 3 2 ^ 5 (2 / + 1) +

Expected output: 3 2 ^ 5 2 1 + / +

0

There are 0 best solutions below