Reputation: 363
If a have the string calculation = '1+1x8'
. How can I convert this into calculation = 1+1*8
? I tried doing something like
for char in calculation:
if char == 'x':
calculation = calculation.replace('x', *)
# and
if char == '1':
calculation = calculation.replace('1', 1)
This clearly doesn't work, since you can't replace just one character with an integer. The entire string needs to be an integer, and if I do that it doesn't work either since I can't convert 'x'
and '+'
to integers
Upvotes: 1
Views: 1431
Reputation: 15588
Adding code to what chepner suggested:
Tokenize '1+12x8' -> ['1', '+', '12', 'x', '8']. Use order of operation '/*+-' -> reduce calculation 1 + (12*8) Return the answer
import re
import operator
operators = {
'/': operator.truediv,
'x':operator.mul,
'+':operator.add,
'-':operator.sub,
}
def op(operators, data):
# apply operating to all occurrences
for p in operators:
while p in data:
x = data.index(p)
replacer = operators.get(p)(int(data[x-1]) , int(data[x+1]))
data[x-1] = replacer
del data[x:x+2]
return data[0]
def func(data):
# Tokenize
d = [i for i in re.split('(\d+)', data) if i ]
# Use order of operations
d = op(operators, d)
return d
s1 = "1+1x8"
s2 = '2-4/2+5'
s = func(s1) # 9
print(s)
t = func(s2) #-5
print(t)
Upvotes: 0
Reputation: 532333
Let's use a more complicated string as an example: 1+12x8
. What follows is a rough outline; you need to supply the implementation for each step.
First, you tokenize it, turning 1+12x8
into ['1', '+', '12', 'x', '8']
. For this step you need to write a tokenizer or a lexical analyzer. This is the step where you define your operators and literals.
Next, you convert the token stream into a parse tree. Perhaps you represent the tree as an S-expression ['+', '1', ['x', '12', '8']]
or [operator.add, 1, [operator.mul, 12, 8]]
. This step requires writing a parser, which requires you to define things like the precedence of your operators.
Finally, you write an evaluator that can reduce your parse tree to a single value. Doing this in two steps might yield
[operator.add, 1, [operator.mul, 12, 8]]
to [operator.add, 1, 96]
[operator.add, 1, 96]
to 97
Upvotes: 5
Reputation: 690
You could write something like:
def parse_exp(s):
return eval(s.replace('x','*'))
and expand for whatever other exotic symbols you want to use.
To limit the risks of eval you can also eliminate bad characters:
import string
good = string.digits + '()/*+-x'
def parse_exp(s):
s2 = ''.join([i for i in s if i in good])
return eval(s2.replace('x','*'))
Edit: additional bonus is that the in-built eval
function will take care of things like parenthesis and general calculation rules :)
Edit 2: As another user pointed out, eval
can be dangerous. As such, only use it if your code will ever only run locally
Upvotes: 0