Since Pastie doesn't seem to be so reliable (at least today):
###########################################
# Ruby quiz #148
# http://www.rubyquiz.com/quiz148.html
# Eric Duminil
# 02/12/2007
#
### It removes unnecesary ().
#
# ruby postfix_to_infix.rb '56 34 213.7 + * 678 -'
# 56*(34+213.7)-678
# =13193.2
#
# ruby postfix_to_infix.rb '1 56 35 + 16 9 - / +'
# 1+(56+35)/(16-9)
# =14
#
# ruby postfix_to_infix.rb '1 2+ 4* 5*'
# (1+2)*4*5
# =60
#
### You can omit spaces between operands and operators
#
# ruby postfix_to_infix.rb '1 2+ 4* 5+ 3-'
# (1+2)*4+5-3
# =14
#
# ruby postfix_to_infix.rb '1 2+ 3 4 + +'
# 1+2+3+4
# =10
#
# ruby postfix_to_infix.rb '1 2 - 3 4 - -'
# 1-2-(3-4)
# =0
#
### You can use either ** or ^
### which actually raises troubles while parsing : is "**" == "* *" or
"**"=="^" ?
#
# ruby postfix_to_infix.rb '2 2 ^ 2 ^'
# (2^2)^2
# =16
#
# ruby postfix_to_infix.rb '2 2 ** 2 **'
# (2**2)**2
# =16
#
# ruby postfix_to_infix.rb '2 3 4 ** **'
# 2**3**4
# =2417851639229258349412352
#
# ruby postfix_to_infix.rb '2 3 ** 4 **'
# (2**3)**4
# =4096
#
### It raises when something's missing
#
# ruby postfix_to_infix.rb '1 2+ 4* 5+ 3'
# postfix_to_infix.rb:94:in `convert_to_infix': ArgumentError
#
#
### No UnaryOperation yet
class Operation
attr_reader :operator, :operands
attr_writer :with_parentheses
def initialize(operator, *operands)
@operator=operator
@operands=operands
@with_parentheses=false
add_parentheses_to_operands_if_necessary!
end
def has_parentheses?
@with_parentheses
end
end
class BinaryOperation<Operation
@@precedence_over={
'+' =>['',''],
#no need to put () before -
'-' =>['','- +'],
'*' => ['- +','- +'],
'/' => ['- +','- + * /'],
'**'=>['- + * / ^ **','- + * /'],
'^'=>['- + * / ^ **','- + * /']
}
def to_s
operands.collect{|operand| if operand.is_a?(Operation) &&
operand.has_parentheses? then
"(#{operand})"
else
operand
end
}.join(operator)
end
private
def add_parentheses_to_operands_if_necessary!
operands.each_with_index{|operand,i|
operators_with_lower_priority=@@precedence_over[operator][i].split(' ')
operand.with_parentheses=operators_with_lower_priority.any?{|o|
operand.operator == o} if operand.is_a?(BinaryOperation)
}
end
end
class Postfix<String
def split_into_operands_and_operators
self.scan(/([\w\.]+|\*+|\+|\/|\-|\^)/).flatten
end
def to_infix
@to_infix||=convert_to_infix
end
def evaluate
eval(self.to_infix.gsub(/\^/,'**'))
end
private
def convert_to_infix
stack=[]
self.split_into_operands_and_operators.each{|term|
if term=~/^[\w\.]+$/ then
stack<<term
else
right_operand,left_operand=stack.pop,stack.pop
stack<<BinaryOperation.new(term,left_operand,right_operand)
end
}
raise ArgumentError unless stack.size==1
stack.first.to_s
end
end
p=Postfix.new(ARGV[0])
puts p.to_infix
puts "=#{p.evaluate}"
###########################################
see http://pastie.caboo.se/124473 for colored syntaxing
Thanks again,
Eric
On 03/12/2007, Artem Voroztsov <artem.voroztsov / gmail.com> wrote:
> All solutions you posted are fun. But now it's time for REAL challenge. :)))
>
> 'a b c d = 1 2 + and = ='
> should be converted to
> 'a = b = ( c = d and 1 + 2 )'
>
> My program does this.
>
> The final task is: having information about operators priorities,
> commutativity/non-commutativity, and associativity type (left or
> right)
> construct OP_STRENGTH
>
> input = 'a b c d = 1 2 + and = ='
>
> #
> OP_STRENGTH = {
> :left => {'and'=>-1, '='=>1, '+'=>2, '-'=>2, '*'=>4, '/'=>4},
> :right => {'and'=>-1, '='=>0 ,'+'=>2, '-'=>3, '*'=>4, '/'=>5}
> }
>
> def parenthesize(triplet, top_op_strength, side)
> q = [ [triplet, top_op_strength, side] ]
> while !q.empty?
> t,top_op_strength,side = q.pop
> if t.is_a?(Array)
> if OP_STRENGTH[side][t[1]] < top_op_strength
> print '( '
> q << ')'
> end
> q << [t[2], OP_STRENGTH[:right][t[1]], :left]
> q << t[1]
> q << [t[0], OP_STRENGTH[:left][t[1]], :right]
> else
> print t, ' '
> end
> end
> end
>
> require 'benchmark'
> puts Benchmark.measure {
> stack = []
> input.strip.split.each do |token|
> case token
> when '*', '+', '/', '-', '=', 'and'
> stack << [stack.pop, token, stack.pop].reverse!
> else
> stack << token
> end
> end
>
> parenthesize(stack.last, 0, :right)
> puts
> }
>
>
> And the second thing.
> For inputs
>
> '0 ' + (1..10000).to_a.join(' - ') + ' *'
> (1..N).to_a.join(' ') + ' /' * (N-1)
>
> where N = 10000 i have benchmark:
>
> 0.282000 0.000000 0.282000
> 0.313000 0.000000 0.313000
>
>