dkolev00
dkolev00

Reputation: 43

I am trying to make a calculator that takes the whole equation and does not use eval()

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

Answers (2)

dkolev00
dkolev00

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

Peter
Peter

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

Related Questions