Python计算器,特别是getNextNumber函数不能正常工作

时间:2017-07-20 01:56:20

标签: python python-3.6

我尝试使用堆栈计算出一个简单的python计算器,它仅适用于负数是第一个且没有负数的情况,但是当出现诸如4 * -2等情况时,它给出了一个错误(我的眼睛在getNextNumber和isNumber和findNextOpr。有没有办法解决这个问题?这里的代码是:

import pdb
class Stack:
    def __init__(self):
        self.container = []
    def isEmpty(self):
        return self.size() == 0
    def push(self, item):
        self.container.append(item)
    def pop(self):
        return self.container.pop()
    def size(self):
        return len(self.container)
class stack:
    class node:
        def __init__(self, value, nextNode):
            self.value = value
            self.nextNode = nextNode
    def __init__(self):
        self.top = None
        self.last = None
        self.size = 0
    def __len__(self):
        return self.size
    def isEmpty(self):
        return self.size == 0
    def push(self, value):
        if self.size == 0:
            self.top = self.last = self.node(value, None)
        else:
            newNode = self.node(value, None)
            newNode.nextNode = self.top
            self.top = newNode
        self.size += 1
    def pop(self):
        if self.size == 0:
            return 'Error: stack.pop'
        elif self.size == 1:
            value = self.top.value
            self.top = self.last = None
            self.size -= 1
            return value
        else:
            value = self.top.value
            self.top = self.top.nextNode
            self.size -= 1
            return value
def findNextOpr(s):
    if len(s) <= 0 or not isinstance(s, str):
        print('Type mismatch error: findNextOpr')
        return 'Type mismatch error: findNextOpr'
    for n in range(len(s)):
        if ord(s[n]) == 42 or ord(s[n]) == 43 or ord(s[n]) == 45 or ord(s[n]) == 47 or ord(s[n]) == 94:
            return n
        else:
            continue
    return -1
def isNumber(s):
    if len(s) == 0 or not isinstance(s, str):
        print('Type mismatch error: isNumber')
        return 'Type mismatch error: isNumber'
    try:
        float(s)
        return True
    except:
        return False
def getNextNumber(expr, pos):
    #pdb.set_trace()
    if len(expr) == 0 or not isinstance(expr, str) or pos < 0 or pos >= len(expr) or not isinstance(pos, int):
        print('Type mismatch error: getNextNumber')
        return None, None, 'Type mismatch error: getNextNumber'
    m = findNextOpr(expr[pos:])
    if m != -1:
        opr = expr[m]
        if isNumber(expr[pos: m + pos]) is True:
            return float(expr[pos: m + pos]), expr[pos + m], m
        elif isNumber(expr[pos:m+pos]) is False:
            if expr[m+1] == '-':
                pos = m+1
                num=getNextNumber(expr,pos)
                return -float(num),None,None
        else:
            return None, None, None
    elif m == -1:
        if isNumber(expr[pos:]) is True:
            return float(expr[pos:]), None, None
        else:
            return None, None, None
def exeOpr(num1, opr, num2):
    if opr == '+':
        return num1 + num2
    elif opr == '-':
        return num1 - num2
    elif opr == '*':
        return num1 * num2
    elif opr == '/':
        if num2 == 0:
            print('Zero division error: exeOpr')
            return 'Zero division error: exeOpr'
        else:
            return num1 / num2
    elif opr == '^':
        return num1 ** num2
    else:
        print('Fatal internal error in exeOpr')
        return 'Fatal internal error in exeOpr'
def _calc(expr):
    if not isinstance(expr, str) or len(expr) <= 0:
        print('Argument error: Line A in eval_expr')
        return 'Argument error: Line A in eval_expr'
    newNumber, newOpr, oprPos = getNextNumber(expr, 0)
    if newNumber is None:
        print('Input formula error: Line B in eval_expr')
        return 'Input formula error: Line B in eval_expr'
    elif newOpr is None:
        return newNumber
    elif newOpr == '+' or newOpr == '-':
        mode = 'add'
        addResult = newNumber
        mulResult = 1
        expResult = 0
    elif newOpr == '*' or newOpr == '/':
        mode = 'mul'
        addResult = 0
        mulResult = newNumber
        expResult = 1
    elif newOpr == '^':
        mode = 'exp'
        addResult = 0
        mulResult = 1
        expResult = newNumber
    pos = oprPos + 1
    opr = newOpr
    while True:
        nextNumber, newOpr, oprPos = getNextNumber(expr, pos)
        if nextNumber is None or pos >= len(expr):
            print('Input formula error: Line C in calc')
            return 'Input formula error: Line C in calc'
        elif newOpr is None:
            if mode == 'add':
                return exeOpr(addResult, opr, nextNumber)
            elif mode == 'mul':
                return exeOpr(mulResult, opr, nextNumber) + addResult
            elif mode == 'exp':
                return exeOpr(expResult, opr, nextNumber) * mulResult + addResult
        oprPos += pos
        pos = oprPos + 1
        if mode == 'add':
            if newOpr == '+' or newOpr == '-':
                addResult = exeOpr(addResult, opr, nextNumber)
                mode = 'add'
            elif newOpr == '*' or newOpr == '/':
                if opr == '+':
                    mulResult = nextNumber
                elif opr == '-':
                    mulResult = -nextNumber
                mode = 'mul'
            elif newOpr == '^':
                if opr == '+':
                    expResult = nextNumber
                elif opr == '-':
                    expResult = - nextNumber
                mode = 'exp'
        elif mode == 'mul':
            if newOpr == '*' or newOpr == '/':
                mulResult = exeOpr(mulResult, opr, nextNumber)
                mode = 'mul'
            elif newOpr == '+' or newOpr == '-':
                addResult += exeOpr(mulResult, opr, nextNumber)
            elif newOpr == '^':
                if opr == '*':
                    expResult = 1 / nextNumber
                mode = 'exp'
        elif mode == 'exp':
            if newOpr == '^':
                expResult = exeOpr(expResult, opr, nextNumber)
                mode = 'exp'
            elif newOpr == '+' or newOpr == '-':
                addResult = exeOpr(expResult, opr, nextNumber) * mulResult + addResult
                mode = 'add'
            elif newOpr == '*' or newOpr == '/':
                mulResult = exeOpr(expResult, opr, nextNumber) * mulResult
                mode = 'mul'
        opr = newOpr
def icheck(expr):
    d = None
    if expr[0] == '-':
        expr = '0' + expr
    for i in range(len(expr)):
        if expr[i] == '(':
            d = i
        elif expr[i] == '':
            continue
        elif d is not None and expr[i] == '-':
            for j in range(i + 1, len(expr)):
                if expr[j] == '':
                    continue
                else:
                    expr = expr[0: d + 1] + '0' + expr[d+1:]
                    d = None
                    break
        else:
            d = None
    return expr
def pcheck(expr):
    expr = expr.replace(' ', '')
    per = Stack()
    for i in range(len(expr)):
        if expr[i] == '(':
            if i != 0 and isNumber(expr[i - 1]) == True:
                print('Omitting Operator')
                return False
            per.push(i)
        elif expr[i] == ')':
            if i != (len(expr) - 1) and isNumber(expr[i + 1]) == True:
                print('Omitting Operator')
                return False
            try:
                per.pop()
            except IndexError:
                print('Parenthesis are unbalanced')
                return False
    return per.isEmpty()
def calc(e, u=None):
    if len(e) == 0:
        return 'Empty String'
    e = e.replace(' ', '')
    if u is None:
        e = icheck(e)
    tf = pcheck(e)
    if tf is False:
        return IndexError
    st = Stack()
    b = None
    for i in range(len(e)):
        pos = i
        if e[i] == '(':
            st.push(i)
        elif e[i] == ')':
            b = st.pop()
            c = i
            break
    if b is None:
        return _calc(e)
    if st.size() == 0 and (pos == len(e) - 1):
        res = _calc(e[b+1:c])
        if len(e) > c:
            e = e[:b] + str(res) + e[c + 1:]
        else:
            e = e[:b] + str(res)
        return _calc(e)
    else:
        res = _calc(e[b + 1: c])
        e = e[:b] + str(res) + e[c + 1:]
        return calc(e, u=1)
print(calc('2.0*-2+5'))
print(calc('-2.0+1'))
print(calc('4*-2'))
print(calc('2+3*(-2 +(-3)*(5^2-2*3^(-2))*(-4))*(2/8+2*(3–1/3))-2/3^2'))
print(calc('1+3-2/30^2/5-1*5*3*4/3-1^2/6/7/8+3-1/2^2*3/2+3+1^2^2+3/3^2'))

1 个答案:

答案 0 :(得分:0)

这是一个预期的问题。为了解决这个问题,电子计算器通常单独使用符号(这在Python中是相同的,导致您的问题)。您可以通过为这些创建运算符类来应用它,为它们指定特定目的。

或者,您可以在输入时强制正确使用paranthesis,或预先检查输入并转换它而不打扰用户,使其成为计算机可用格式(添加paranthesis或无论如何)。