So, I have a lot of information for you, but it's very relevant. I also drastically changed your code:
Easily separating the operators and the numbers will not work unless you require something such as there being parentheses/spaces around every negative number. But not only will this make it so that you cannot enter regular, unformatted equations in your calculator, it also will require you to treat negative numbers as special. Which they are, but this is not necessary. This is because you can basically ignore that they are negative. The code changes I propose will more easily let you handle any operator as well.
Any negative number can be broken down into an operation: -x is the same as 0 - x. The question is: when should the zero be added? There are two cases: when the first input is a negative sign and when there is a negative sign after another operator.
All you need to do is add some code to handle those conditions. Let us look at some examples:
>>> -2+5
3
>>> 5+-2
3
>>> (1/9)^(-1/2)
3
>>> (2+(-1))*5-2
43
The problem with negatives in your approach comes from the fact that when you separate the operators from the numbers, you do not know what should come next: an operator or a number (this is a problem for all the above examples).
One solution is to keep track of the locations of all the numbers! Doing this will allow you to know exactly how many operators are in between each number and you can figure out which numbers are negative (or where you should add a zero) through that.
I have rewritten your code for this and it is pretty different but the main idea is still there. See the code below:
import re
# Takes care of applying the operation on the left number given the right number
def applyOperation(operator, left, right):
answer = left
if operator == '(':
return NotImplemented
elif operator == ')':
return NotImplemented
elif operator == '^':
return NotImplemented
elif operator == '*': answer *= int(right)
elif operator == '/': answer /= int(right)
elif operator == '+': answer += int(right)
elif operator == '-': answer -= int(right)
else:
print("Error. Only '*', '/', '+',and '-' are allowed at the moment.")
# You could also allow a period, exponents (^), modulo, exponential, etc.
exit(1)
return answer
def calc(equation):
"""
Magical calculator (It handles negative numbers)
DISCLAIMER:
-This version does not allow parentheses or float inputs (but does allow float outputs)
-It also does not follow the order of operations
"""
numIndices = [m.span() for m in re.finditer("\d+", equation)]
prevNumber = 0
prevEnd = ''
for numIndex in numIndices:
number = float(equation[numIndex[0]:numIndex[1]])
# If at the start, just add the number
if numIndex[0] == 0:
prevNumber = number
prevEnd = numIndex[1]
continue
# Starting at the second spot of the equation is special
if numIndex[0] == 1:
# Remember this for order of operations (if implemented)
if equation[0] == "(":
# I think handling these would be best done recursively
# Or you could split on all parentheses and compute each in turn
# Or ...
return NotImplemented
# It's a negative number
elif equation[0] == "-":
prevNumber -= number
prevEnd = numIndex[1]
continue
else:
print("Error. Only numbers, '-' and '(' are allowed at the "
+"beginning of the equation.")
# You could allow a period as well.
exit(1)
# If reached here, then should have passed the first number
# Extract relevant operators and remove any spaces
operators = equation[prevEnd:numIndex[0]]
operators = "".join(operators.split())
if len(operators) == 1:
prevNumber = applyOperation(operators[0], prevNumber, number)
elif len(operators) == 2:
if (operators[1] == '-'):
prevNumber = applyOperation(operators[0], prevNumber, -number)
else:
print("Error. Currently, the second operator must always be a '-'.")
exit(1)
# If it reaches here, then parentheses are probably involved
# or syntax is probably incorrect
else:
print("Error. Only two operators are currently allowed between numbers."
+ " The second one always being a '-'.")
# You could allow all sorts of nesting with parentheses if you want.
exit(1)
prevEnd = numIndex[1]
# Do not display the decimal places if they are all 0
prevNumber = int(prevNumber) if prevNumber-int(prevNumber) == 0 else prevNumber
print("Equation:", equation,"\nAnswer:",prevNumber)
while True:
calc(input('>>> '))
Calculators are not a joke! xD
P.S. It also accepts equations of just letters.