# You are building an educational website and want # to create a simple calculator for students to use. # The calculator will only allow addition and subtraction # of non-negative integers. # We also want to allow parentheses in our input. # Given an expression string using # the "+", "-", "(", and ")" # operators like "5+(16-2)", write a function to parse the # string and evaluate the result. import re class Calculate: __NUMS = re.compile(r"\d+") @classmethod def tokens(cls, s): pos = 0 n = len(s) while pos < n: m = Calculate.__NUMS.match(s, pos) if m: yield int(m.group(0)) pos += len(m.group(0)) if pos < n: yield s[pos] pos += 1 def __init__(self, s): self.__tokens = [] for t in Calculate.tokens(s): self.__tokens.append(t) class Context: def __init__(self): self.__stack = [] self.__op = None def __str__(self): return f"Context({self.stack}){'OP: ' + str(self.op) if self.op else ''}" @property def op(self): return self.__op @op.setter def op(self, v): self.__op = v @property def stack(self): return self.__stack def nonEmpty(self): return len(self.stack) != 0 @property def val(self): if self.nonEmpty(): return self.stack[-1] return None def __deal_with_val_in_context(self, cx, v): if cx.op: left = cx.stack.pop() cx.stack.append(cx.op(left, v)) cx.op = None else: cx.stack.append(v) def value(self): l = [] cx = Calculate.Context() for t in self.__tokens: if type(t) is int: self.__deal_with_val_in_context(cx, t) continue if t == '(': l.append(cx) cx = Calculate.Context() continue if t == ')': my_v = cx.val cx = l.pop() if my_v is not None: self.__deal_with_val_in_context(cx, my_v) continue if t == '+': cx.op = lambda a, b: a + b continue if t == '-': cx.op = lambda a, b: a -b return cx.val if __name__ == '__main__': tests = [ ("6+9-12", 3), ("1+2-3+4-5+6-7", -2), ("100+200+300", 600), ("1-2-3-0", -4), ("255", 255), ("5+16-((9-6)-(4-2))+1", 21), ("22+(2-4)", 20), ("6+9-12", 3), ("((1024))", 1024), ("1+(2+3)-(4-5)+6", 13), ("255", 255)] for t in tests: expr = t[0] correct = t[1] v = Calculate(expr).value() res = "OK" if v == correct else "FAIL" print(f"{res} Calculate({expr}) = {v} [expected {correct}]") # OK Calculate(6+9+12) = 3 [expected 3] # OK Calculate(1+2-3+4-5+6-7) = -2 [expected -2]