1 Востаннє редагувалося Betterthanyou (05.03.2023 01:16:23)

Тема: [Пост] Калькулятор який "знає" послідовність математичних дій

Зробив калькуляторі який зможе порахувати
1) (4/9/4-(52/462*(-9*(6*5-6-8*(47/5*(8-9)*8)))))-6*9-6+3+5*5-9-.83
2) 7-9*(4/(5*(5-3)*(4*4)))*8
3) 7-(1-1)+(-1)
та інше що використовує цілі, або з плаваючою точкою числа.
Мат. операції *,/,-,+.
Дужки (,)

НЕ БУДЕ працювати без явного знаку множення. Наприклад "(4(9-6))"

"(4(9-6))" - Це легко виправити, якщо комусь цікаво пишіть, я виправлю.

Метод calculate отримує вираз як вхідні дані, встановлює початкову позицію на 0, а потім викликає метод parse_expression для розбору та обчислення виразу.

Метод parse_expression спочатку викликає метод parse_term для отримання значення лівого операнда. Потім він перевіряє, чи є в виразі ще оператори і якщо вони є або '+' або '-', то він викликає відповідний метод (parse_term для '+' та '-' операторів) для розбору правого операнда, а потім виконує відповідну операцію. Він продовжує це робити, доки всі оператори виразу не будуть оброблені та оцінені.

Метод parse_term спочатку викликає метод parse_factor для отримання значення лівого операнда. Потім він перевіряє, чи є в виразі ще оператори і якщо вони є або '*' або '/', то він викликає відповідний метод (parse_factor для '*' та '/' операторів) для розбору правого операнда, а потім виконує відповідну операцію. Він продовжує це робити, доки всі оператори виразу не будуть оброблені.

Метод parse_factor спочатку перевіряє, чи поточний символ у виразі є '('. Якщо це так, то він викликає метод parse_expression для обробки вкладеного в дужки підвиразу. Якщо поточний символ є '-', він встановлює значення як від'ємне і викликає метод parse_number для розбору числа. В іншому випадку він викликає метод parse_number для розбору числа.

Метод parse_number знаходить початок числа та продовжує пересувати позицію, доки не досягне кінця числа. Потім він повертає число у форматі float. Якщо число не знайдено, він створює ValueError.

class Calculator:
    def calculate(self, expr):
        self.expr = expr
        self.pos = 0
        return self.parse_expression()

    def parse_expression(self):
        value = self.parse_term()
        while self.pos < len(self.expr) and self.expr[self.pos] in '+-':
            op = self.expr[self.pos]
            self.pos += 1
            if op == '+':
                value += self.parse_term()
            else:
                value -= self.parse_term()
        return value

    def parse_term(self):
        value = self.parse_factor()
        while self.pos < len(self.expr) and self.expr[self.pos] in '*/':
            op = self.expr[self.pos]
            self.pos += 1
            if op == '*':
                value *= self.parse_factor()
            else:
                value /= self.parse_factor()
        return value
        
    def parse_factor(self):
        if self.expr[self.pos] == '(':
            self.pos += 1
            value = self.parse_expression()
            if self.expr[self.pos] != ')':
                raise ValueError("Expected ')' at position " + str(self.pos))
            self.pos += 1
        else:
            if self.expr[self.pos] == '-':
                self.pos += 1
                value = -self.parse_number()
            else:
                value = self.parse_number()
        return value
        
    def parse_number(self):
        start = self.pos
        while self.pos < len(self.expr) and (self.expr[self.pos].isdigit() or self.expr[self.pos] == '.'):
            self.pos += 1
        if start == self.pos:
            raise ValueError("Invalid number at position " + str(start))
        return float(self.expr[start:self.pos])

calc = Calculator()
print(calc.calculate("(4/9/4-(52/462*(-9*(6*5-6-8*(47/5*(8-9)*8)))))-6*9-6+3+5*5-9-.83"))
Подякували: koala1

2

Re: [Пост] Калькулятор який "знає" послідовність математичних дій

Коли робив був схожу задачку, то всю роботу з обчислення та парсингу переклав на стандартний eval, перед цим лише перевіривши вираз регексом без справжнього парсингу.

Прихований текст
#from cgi import parse_qs, escape
from urllib.parse import parse_qs
#from html import escape
import re

def check_expr(expr):
    if not re.match(r'^\(*-?([0-9]+\.)?[0-9]+(([-+*/%]|//|\*\*)\(*-?([0-9]+\.)?[0-9]+\)*)*\)*$',expr):
        return False
    expr=re.sub(r'[^()]', '', expr)
    lvl=0
    for c in expr:
        if c=='(':
            lvl+=1
        elif c==')':
            lvl-=1
        if lvl<0:
            return False
    return lvl==0

def application(environ, start_response):
    parameters = parse_qs(environ.get('QUERY_STRING', ''))
    expr=parameters['expr'][0] if 'expr' in parameters else ''
    # verify expr using regex:
    err=''
    if expr:
        if not check_expr(expr):
            err='<span style="color:red"> - Синтаксична помилка</span>'
        else:
            try:
                expr=expr+' = '+str(eval(expr))
            except ZeroDivisionError:
                err='<span style="color:red"> - Ділення на 0</span>'
            except OverflowError:
                err='<span style="color:red"> - Результат надто великий</span>'

    start_response('200 OK', [('Content-Type', 'text/html; charset=UTF-8')])
    return [
        b"""<form> <input name=expr> <input type=submit></form>""",
        expr.encode(),
        err.encode()
    ]

if __name__=='__main__':
    from wsgiref.simple_server import make_server
    httpd = make_server('', 8000, application)
    print ("Serving HTTP on port 8000...")

    # Respond to requests until process is killed
    httpd.serve_forever()
Подякували: Betterthanyou, koala2