Reputation: 43
I am trying to make a calculator that doesn't use eval() and take the whole equation as a string. Also I can't use any libraries, modules, etc. I've managed to make something but I can't figure out how to make it to first do the multiplication and division and then the rest. It doesn't give me an error but it does this: 4 + 4 = 8
4 + 4 * 4 = 20
4 + 4 * 4 + 4 = 4
Edit: So I found where the problem was, but it still doesn't function right. The problem was that the code doesn't even reach the part where it finds the "*". I'll mark with an arrow where it doesn't reach it.
Here is the code and thanks in advance:
print("Calculator")
# All the numbers
def numbers(num):
return(
num == "0"
or num == "1"
or num == "2"
or num == "3"
or num == "4"
or num == "5"
or num == "6"
or num == "7"
or num == "8"
or num == "9"
)
# All the operators
def operator(oprt):
return(
oprt == "+"
or oprt == "-"
or oprt == "*"
or oprt == "/"
)
# Removes all the spaces
def remove_spaces(string):
string = string.replace(" ", "")
return string
# Does the math between two numbers
def operation(string, num1, num2):
if string == "+":
return num1 + num2
if string == "-":
return num1 - num2
if string == "*":
return num1 * num2
if string == "/":
return num1 / num2
# Tests how long the number is
def test_number(numstr):
n = 0
num = ""
try:
while numbers(numstr[n]):
num += numstr[n]
n += 1
except:
pass
return(int(num), n)
# Solves the equation
def eval_equation(eq):
negative = False
# Removes the spaces
eq = remove_spaces(eq)
while True:
try:
# Checks if the first number is negative
if eq[0] == "-":
negative = True
eq = eq[1:]
# Solves the multiplication first
i = 0
eqTemp = ""
if "*" in eq:
try:
while i < len(eq):
if eq[i] == "+" or eq[i] == "-" or eq[i] == "/":
eqTemp = eqTemp + eq[:i + 1]
print(f"eqTemp = {eqTemp}")
eq = eq[i + 1:]
print(f"eq = {eq}")
elif eq[i] == "*": # <-------this is the problem----
break
print(f"eqTemp = {eqTemp}")
print(f"eq = {eq}")
i += 1
except:
i = 0
# Checks the lenght of the number
number1 = test_number(eq)[0]
# Returns the "-" in the negative number
if negative == True:
number1 = -number1
negative = False
# Removes the first number from the string to continue with the next
endNumber1 = test_number(eq)[1]
eq = eq[endNumber1:]
# Checks for any more numbers
if eq == "":
return number1
# This is the operator sign
op = eq[0]
eq = eq[1:]
# Repeats the same process with the other number
number2 = test_number(eq)[0]
endNumber2 = test_number(eq)[1]
result = operation(op, number1, number2)
# Takes the result and passes it as to the first number along with the rest of the equation
number1 = result
eq = str(number1) + eq[endNumber2:]
eq = eqTemp + eq
except Exception as error:
print(error)
break
return number1
# Main function
if __name__ == "__main__":
while True:
equation = input(": ")
print(eval_equation(equation))
Upvotes: 3
Views: 144
Reputation: 43
So I fixed it. I'm not sure how... but I fixed it. I just need to figure out how to add variables to the equation now :) . Here is the code and thanks to everybody who gave ideas:
print("Calculator")
# All the numbers
def numbers(num):
return num in {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}
# All the operators
def operator(oprt):
return oprt in {"+", "-", "*", "/"}
# Removes all the spaces
def remove_spaces(string):
string = string.replace(" ", "")
return string
# Does the math between two numbers
def operation(string, num1, num2):
if string == "+":
return num1 + num2
if string == "-":
return num1 - num2
if string == "*":
return num1 * num2
if string == "/":
return int(num1 / num2)
# Tests how long the number is
def test_number(numstr):
n = 0
num = ""
try:
while numbers(numstr[n]):
num += numstr[n]
n += 1
except:
pass
return(int(num), n)
# Solves the equation
def eval_equation(eq):
negative = False
# Removes the spaces
eq = remove_spaces(eq)
while True:
try:
# Checks if the first number is negative
if eq[0] == "-":
negative = True
eq = eq[1:]
# Solves the multiplication first
i = 0
eqTemp = ""
if "*" in eq:
try:
while i < len(eq):
if eq[i] in {"+", "-", "/"}:
eqTemp = eqTemp + eq[:i + 1]
#print(f"eqTemp = {eqTemp}")
eq = eq[i + 1:]
#print(f"eq = {eq}")
pass
if numbers(eq[i]) == True:
pass
if eq[i] == "*":
break
i += 1
except IndexError:
i = 0
# Solves the division first
i = 0
eqTempDiv = ""
if "/" in eq:
try:
while i < len(eq):
if eq[i] in {"+", "-", "*"}:
eqTempDiv = eqTempDiv + eq[:i + 1]
#print(f"eqTemp = {eqTemp}")
eq = eq[i + 1:]
#print(f"eq = {eq}")
pass
if numbers(eq[i]) == True:
pass
if eq[i] == "/":
break
i += 1
except IndexError:
i = 0
# Checks the lenght of the number
number1 = test_number(eq)[0]
# Returns the "-" in the negative number
if negative == True:
number1 = -number1
negative = False
# Removes the first number from the string to continue with the next
endNumber1 = test_number(eq)[1]
eq = eq[endNumber1:]
# Checks for any more numbers
if eqTempDiv == "":
if eqTemp == "":
if eq == "":
return number1
# This is the operator sign
op = eq[0]
eq = eq[1:]
# Repeats the same process with the other number
number2 = test_number(eq)[0]
endNumber2 = test_number(eq)[1]
result = operation(op, number1, number2)
# Takes the result and passes it as to the first number along with the rest of the equation
number1 = result
eq = str(number1) + eq[endNumber2:]
eq = eqTemp + eqTempDiv + eq
#print(f"eqTemp final = {eqTemp}")
#print(f"eq final = {eq}")
except Exception as error:
print(error)
break
return number1
# Main function
if __name__ == "__main__":
while True:
equation = input(": ")
print(eval_equation(equation))
Upvotes: 0
Reputation: 3495
Edit: Sorry, gotta get back to work, wasn't able to figure out your exact problem. I would suggest starting over on the eval_equation
function as it's quite messy, and will be prone to bugs if you continue adding to it.
Unrelated to the actual question, here's an example of how you might improve a couple of functions a bit. Note the use of in
, the docstrings, as well as a more clear function name.
def is_num(num):
"""Determine if the character is a number."""
return num in '0123456789'
def is_oprt(oprt):
"""Determine if the character is an operator."""
return oprt in '+-*/'
Your test_number
function also can be optimised a little by iterating over the string rather than using while
with try/except
. It's a bit more personal preference but this is how I'd do it:
def get_num(numstr):
"""Gets the number at the start of a string."""
num = []
for i, c in enumerate(numstr):
if not is_num(c):
break
num.append(c)
try:
return int(''.join(num)), i + 1
except ValueError:
return 0, 0
One other syntax suggestion:
number2 = test_number(eq)[0]
endNumber2 = test_number(eq)[1]
Is the same as:
number2, endNumber2 = test_number(eq)
Upvotes: 2