Simple Calculator

# 問題

文字列として与えられる数式を計算するプログラムを書け.

1
print(compute("2*3+5/6*3+15")) # => 23.5

# 答え

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
from enum import Enum, auto
class Op(Enum):
    ADD = auto()
    SUB = auto()
    MUL = auto()
    DIV = auto()
    NOP = auto()

def priority(op):
    if op == Op.ADD or op == Op.SUB:
        return 1
    elif op == Op.MUL or op == Op.DIV:
        return 2
    else: # op == Op.NOP
      return 1

def compute(s):
    num_stack = []
    op_stack = []

    def parse_num(s, i):
        buf = ""
        while i < len(s) and s[i].isdigit():
            buf += s[i]
            i += 1
        return int(buf)

    def parse_op(s, i):
        if i < len(s):
            op_str = s[i]
            if op_str == "+":
                return Op.ADD
            elif op_str == "-":
                return Op.SUB
            elif op_str == "*":
                return Op.MUL
            elif op_str == "/":
                return Op.DIV
        return Op.NOP

    def apply(next_op, num_stack, op_stack):
        while 2 <= len(num_stack) and 1 <= len(op_stack):
            if priority(next_op) <= priority(op_stack[-1]):
                right = num_stack.pop()
                op = op_stack.pop()
                left = num_stack.pop()

                if op == Op.ADD:
                    num_stack.append(left + right)
                elif op == Op.SUB:
                    num_stack.append(left - right)
                elif op == Op.MUL:
                    num_stack.append(left * right)
                elif op == Op.DIV:
                    num_stack.append(left / right)
                else: # op == Op.NOP
                    num_stack.append(right)
            else:
                break

    i = 0
    while i < len(s):
        num = parse_num(s, i)
        num_stack.append(num)
        i += len(str(num))
        if len(s) <= i:
            break

        next_op = parse_op(s, i)
        i += 1

        apply(next_op, num_stack, op_stack)
        op_stack.append(next_op)

    apply(Op.NOP, num_stack, op_stack)

    if len(num_stack) == 1 and len(op_stack) == 0:
        return num_stack.pop()
    else:
        return 0

s = "2*3+5/6*3+15"

print(compute(s)) # => 23.5
Hugo で構築されています。
テーマ StackJimmy によって設計されています。