Как изменить postfix (), чтобы он мог поддерживать использование скобок - PullRequest
0 голосов
/ 18 апреля 2019

Я пишу функцию с именем calculator (expr), которая принимает инфиксное выражение, преобразует его в постфиксное выражение (вызывая postfix ()), а затем оценивает указанное выражение с помощью Stack ADT.

Мне нужно изменить postfix (), чтобы он мог принимать выражения с круглыми скобками и возвращать результат результирующего выражения postfix (конечно, только если круглые скобки сбалансированы).

Как мне реализовать это в Python 3?

Я действительно не знаю, что делать. Я рисую заготовки.

def findNextOpr(txt):

        """
            >>> findNextOpr('  3*   4 - 5')
            3
            >>> findNextOpr('8   4 - 5')
            6
            >>> findNextOpr('89 4 5')
            -1
        """
    if not isinstance(txt,str) or len(txt)<=0:
        return "error: findNextOpr"

    # --- YOU CODE STARTS HERE
    operators = '+-*/^'
    for i in range(len(txt)):
        if txt[i] in operators:
            return i

    return -1



def isNumber(txt):
    """
        >>> isNumber('1   2 3')
        False
        >>> isNumber('-  156.3')
        False
        >>> isNumber('     29.99999999    ')
        True
        >>> isNumber('    5.9999x ')
        False
    """
    if not isinstance(txt, str) or len(txt)==0:
        return "error: isNumber"
    # --- YOU CODE STARTS HERE
    try:
        float(txt)
        return True
    except Exception as other:
        return False




def getNextNumber(expr, pos):
    """
        >>> getNextNumber('8  +    5    -2',0)
        (8.0, '+', 3)
        >>> getNextNumber('8  +    5    -2',4)
        (5.0, '-', 13)
        >>> getNextNumber('4.5 + 3.15         /  -5',20)
        (-5.0, None, None)
        >>> getNextNumber('4.5 + 3.15         /   5',10)
        (None, '/', 19)
    """

    if not isinstance(expr, str) or not isinstance(
        pos, int) or len(expr)==0 or pos<0 or pos>=len(expr):
        return None, None, "error: getNextNumber"
    # --- YOU CODE STARTS HERE

    subexpr = expr[pos:].strip()
    if subexpr[0] == '-':
        posn = expr.find('-', pos)
        oprPos = findNextOpr(expr[posn + 1: ])

        if oprPos != -1:
            oprPos = oprPos + posn + 1 - pos

    else:
        oprPos = findNextOpr(expr[pos:])

    if oprPos != -1:
        oprPos = oprPos + pos
        nextOpr = expr[oprPos]
        newNumber = expr[pos:oprPos]

    else:
        nextOpr, oprPos = None, None
        newNumber = expr[pos:]

    if isNumber(newNumber):
        return float(newNumber), nextOpr, oprPos

    else :
        return None, nextOpr, oprPos


class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

    def __str__(self):
        return "Node({})".format(self.value)

    __repr__ = __str__


class Stack:
    '''
        >>> x=Stack()
        >>> x.pop()
        'Stack is empty'
        >>> x.push(2)
        >>> x.push(4)
        >>> x.push(6)
        >>> x
        Top:Node(6)
        Stack:
        6
        4
        2
        >>> x.pop()
        6
        >>> x
        Top:Node(4)
        Stack:
        4
        2
        >>> len(x)
        2
        >>> x.peek()
        4
    '''
    def __init__(self):
        self.top = None

        self.item = 0

    def __str__(self):
        temp=self.top
        out=[]
        while temp:
            out.append(str(temp.value))
            temp=temp.next
        out='\n'.join(out)
        return ('Top:{}\nStack:\n{}'.format(self.top,out))

    __repr__=__str__

    def isEmpty(self):
        #write your code here
        if self.top is None :
            return True
        else :
            return False


    def __len__(self):
        #write your code here
        length = 0
        temp = self.top
        while temp:
            length += 1
            temp = temp.next

        return length

    def peek(self):
        #write your code here
        if self.top is None:
            return "Stack is is empty"
        else:
            return self.top.value

    def push(self,value):
        #write your code here
        newnode = Node(value)
        self.item = value
        newnode.next = self.top
        self.top  = newnode


    def pop(self):
        #write your code here
        if self.top is None:
            return "Stack is empty"
        else:
            element = self.top.value
            self.top = self.top.next
            return element

parentheses = ['(', ')']

def postfix(expr):
    if not balparentheses(expr):
        return "error, invalid expression"
    number, opr, oprPos = getNextNumber(expr, 0)

    if number is None:
        return "error, invalid expression"

    elif opr is None:
        return float(expr)

    pos = oprPos + 1
    postfix = []
    postfixstack = Stack()
    postfix = [str(number)]
    postfixstack.push(opr)
    precedence = {'+' : 1, '-' : 1, '*' : 2, '/' : 2, '^' : 3, '(' : 4, ')' : 4}


    while True :
        number, opr, oprPos = getNextNumber(expr, pos)


        if number is None:
            return "error, invalid expression"

        if opr is None and number is None:
            return postfix

        postfix.append(str(number))
        if opr is not None:
            while not postfixstack.isEmpty():
                if precedence[opr] > precedence[postfixstack.peek()]:
                    break
                else:
                    postfix.append(str(postfixstack.pop()))
            postfixstack.push(opr)

        else:
            while not postfixstack.isEmpty():
                postfix.append(str(postfixstack.pop()))
            return " ".join(postfix).strip()

        pos = oprPos + 1





def balparentheses(txt): #function that checks whether parentheses are balanced
    s = Stack()
    balanced = True
    index = 0
    while index < len(txt) and balanced:
        symbol = txt[index]
        if symbol == '(':
            s.push(symbol)
        else:
            if symbol == ')':
                balanced = False
            else:
                s.pop()

        index += 1
    if balanced and s.isEmpty():
        return True
    else:
        return False


def compute(opr, num1, num2):
    if opr == '+':
        return num1 + num2
    elif opr == '*':
        return num1 * num2
    elif opr == '-' :
        return num1 - num2
    elif opr == '/':
        try:
            return num1 / num2
        except ZeroDivisionError:
            return "error, invalid expression"
    elif opr == '^':
        return num1 ** num2

def calculator(expr):

    oplist = ['+', '-', '/', '*', '^']
    numbers = [str(float(num)) for num in range(10)]
    eval_stack = Stack()
    eval_expr = postfix(expr)
    alist = eval_expr.split()

    for item in alist:
        if item in numbers:
            eval_stack.push(float(item))

        else:
            op2 = eval_stack.pop()
            op1 = eval_stack.pop()
            result = compute(item, op1, op2)
            eval_stack.push(result)


    return eval_stack.pop()

calculator(' -2 / (-4) * (3 - 2*( 4- 2^3)) + 3') должен вернуть 8.5. Вместо этого он ничего не возвращает. (То же самое для остальных)

calculator('((2))') должен вернуть 2,0.

calculator('2*(4+2*(5-3^2)+1)+4') должен вернуть -2,0

calculator('(-2)*10 - 3*(2 - 3*2)) ') должен возвращать «ошибка, недопустимое выражение»

calculator('(-2)*10 - 3*/(2 - 3*2) ') должен возвращать «ошибка, недопустимое выражение»

...