-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcalculator v2.py
140 lines (111 loc) · 4.11 KB
/
calculator v2.py
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import re
# https://www.codewars.com/kata/5235c913397cbf2508000048/train/python
'[\/\+\*\-\(\)]' # all operators
'\(.+\)' # expression in brackets
'\d+ [\/\*] \d+' # expression for mult and div
'\d+ [\+\-] \d+' # expression for mult and div
def div(operand_left, operand_right):
return operand_left / operand_right
def mult(operand_left, operand_right):
return operand_left * operand_right
def add(operand_left, operand_right):
return operand_left + operand_right
def sub(operand_left, operand_right):
return operand_left - operand_right
def search_in_brackets(s):
left = s.index('(')
right = left + 1
flag = 1
for i in range(right, len(s)+1):
if s[right] == ')':
flag -= 1
elif s[right] == '(':
flag += 1
right = i
if flag == 0:
return left, right
class Calculator(object):
operations = {'*': mult, '/': div, '+': add, '-': sub}
def evaluate(self, string):
lfs = re.findall(r'\-*\d+\.\d+|\-*\d+|[\/\+\*\-\(\)]', string)
oper = re.findall(r'[\/\+\*\-\(\)](?= )', string)
if len(oper) < 1:
return float(string)
elif len(oper) == 1:
return float(self.operations[lfs[1]](float(lfs[0]), float(lfs[2])))
while '(' in lfs:
rng = search_in_brackets(lfs)
lfs = lfs[:rng[0]] + [str(self.evaluate(" ".join(lfs[rng[0]+1:rng[1]-1])))] + lfs[rng[1]:]
while '*' in lfs or '/' in lfs:
if len(lfs) == 3:
return self.evaluate(' '.join(lfs))
if '*' in lfs and '/' in lfs:
ind = min(lfs.index('*'), lfs.index('/'))
elif '*' in lfs:
ind = lfs.index('*')
else:
ind = lfs.index('/')
lfs = lfs[: ind-1] + [str(self.evaluate(" ".join(lfs[ind-1:ind+2])))] + lfs[ind+2:]
while '+' in lfs or '-' in lfs:
if len(lfs) == 3:
return self.evaluate(' '.join(lfs))
if '+' in lfs and '-' in lfs:
ind = min(lfs.index('+'), lfs.index('-'))
elif '+' in lfs:
ind = lfs.index('+')
else:
ind = lfs.index('-')
lfs = lfs[: ind - 1] + [str(self.evaluate(" ".join(lfs[ind - 1:ind + 2])))] + lfs[ind + 2:]
return float(lfs[0])
calc = Calculator()
# simple test
print(calc.evaluate('2 + 2'))
print(calc.evaluate('9 / 3'))
print(calc.evaluate('7 * 3'))
print(calc.evaluate('8 - 2'))
# mul and division test
print(calc.evaluate('9 / 3 * 4'))
print(calc.evaluate('7 * 3 * 2 / 6'))
# brackets with mul and div
print(calc.evaluate('9 / (3 * 3)'))
print(calc.evaluate('54 / (3 * (10 / 5))'))
# add and sub
print(calc.evaluate('7 + 3 - 2 + 6'))
print(calc.evaluate('54 - (3 + (10 / 5))'))
print(calc.evaluate('2 / 2 + 3 * 4 - 6'))
print(calc.evaluate('-5.1 + 3 * -4'))
# best solution from codewars
from operator import add, sub, mul, truediv
FIRST = {'*' : mul, '/': truediv}
SECOND = {'+': add, '-': sub}
class Calculator(object):
def evaluate(self, string):
tokens = [float(t) if t.isdigit() or '.' in t else t for t in string.split()]
while True:
for (i, token) in enumerate(tokens):
op = FIRST.get(token)
if op:
tokens[i - 1 : i + 2] = [op(tokens[i - 1], tokens[i + 1])]
break
else:
ret = tokens[0]
for i in range(1, len(tokens), 2):
ret = SECOND[tokens[i]](ret, tokens[i + 1])
return ret
calc = Calculator()
# simple test
print(calc.evaluate('2 + 2'))
print(calc.evaluate('9 / 3'))
print(calc.evaluate('7 * 3'))
print(calc.evaluate('8 - 2'))
# mul and division test
print(calc.evaluate('9 / 3 * 4'))
print(calc.evaluate('7 * 3 * 2 / 6'))
# brackets with mul and div
print(calc.evaluate('9 / (3 * 3)'))
print(calc.evaluate('54 / (3 * (10 / 5))'))
# add and sub
print(calc.evaluate('7 + 3 - 2 + 6'))
print(calc.evaluate('54 - (3 + (10 / 5))'))
print(calc.evaluate('2 / 2 + 3 * 4 - 6'))
# print(calc.evaluate('-5.1 + 3 * -4')) # unsupport negative number for solution from codewars