Created
July 18, 2012 22:50
-
-
Save numbata/3139500 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Example | |
> ./rpn.rb '3 + 4 * 2 / (1 - 5) * 2' | |
RPN: 3 4 2 * 1 5 - / 2 * + | |
Result: -1.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
class RPN | |
class Token < String | |
OPS_PRIORITY_MAP = [ | |
'', | |
%w(- +), | |
%w(* /) | |
] | |
def priority | |
OPS_PRIORITY_MAP.index{|ops| ops.include? self} || 0 | |
end | |
def operator? | |
OPS_PRIORITY_MAP.flatten.include? self | |
end | |
def open_bracket? | |
self == '(' | |
end | |
def close_bracket? | |
self == ')' | |
end | |
end | |
def self.transform(expression) | |
result = [] | |
operators = [] | |
self.operands(expression).each do |token| | |
if token.operator? | |
if operators.last && token.priority <= operators.last.priority | |
result << operators.pop | |
end | |
operators << token | |
elsif token.close_bracket? | |
until operators.last.open_bracket? do | |
result << operators.pop | |
end | |
operators.pop | |
elsif token.open_bracket? | |
operators << token | |
else | |
result << token | |
end | |
end | |
(result + operators.reverse).join(' ') | |
end | |
def self.calc(expression) | |
stack = [] | |
operands(expression).each do |token| | |
if token.operator? | |
b = stack.pop.to_f | |
a = stack.pop.to_f | |
stack << a.send(token.to_s, b) | |
else | |
stack << token | |
end | |
end | |
stack.last | |
end | |
private | |
# Split string to operators | |
# | |
# @param String expression | |
# @return Array | |
def self.operands expression | |
ops = Token::OPS_PRIORITY_MAP.flatten | |
expression.split(/(?:\s+|(?=[0-9]+)(?<![0-9])|(?=[#{ops.join}()]))/).map{|x| Token.new(x)} | |
end | |
end | |
expression = ARGV.join(' ') | |
rpn_expression = RPN.transform(expression) | |
puts "RPN: #{rpn_expression}" | |
result = RPN.calc(rpn_expression) | |
puts "Result: #{result}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment