Initial commit – AufmaßCreater v2.35
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
"""Mathematical expression evaluator with precedence (Punkt vor Strich).
|
||||
Supports +, -, *, /, (, ), and decimal numbers. Safe – no eval()."""
|
||||
|
||||
import re
|
||||
from decimal import Decimal, InvalidOperation
|
||||
|
||||
TOKEN_NUM = 'NUM'
|
||||
TOKEN_PLUS = '+'
|
||||
TOKEN_MINUS = '-'
|
||||
TOKEN_MUL = '*'
|
||||
TOKEN_DIV = '/'
|
||||
TOKEN_LPAR = '('
|
||||
TOKEN_RPAR = ')'
|
||||
|
||||
def tokenize(expr):
|
||||
tokens = []
|
||||
i = 0
|
||||
while i < len(expr):
|
||||
c = expr[i]
|
||||
if c in ' \t':
|
||||
i += 1
|
||||
continue
|
||||
if c in '+-*/()':
|
||||
tokens.append(c)
|
||||
i += 1
|
||||
elif c.isdigit() or c == '.':
|
||||
start = i
|
||||
had_dot = False
|
||||
while i < len(expr) and (expr[i].isdigit() or (expr[i] == '.' and not had_dot)):
|
||||
if expr[i] == '.':
|
||||
had_dot = True
|
||||
i += 1
|
||||
tokens.append(('NUM', expr[start:i]))
|
||||
else:
|
||||
raise ValueError(f"Ungültiges Zeichen: '{c}'")
|
||||
return tokens
|
||||
|
||||
def parse_primary(tokens, pos):
|
||||
if pos >= len(tokens):
|
||||
raise ValueError("Erwarte Zahl oder (")
|
||||
tok = tokens[pos]
|
||||
if isinstance(tok, tuple) and tok[0] == 'NUM':
|
||||
return Decimal(tok[1]), pos + 1
|
||||
if tok == '(':
|
||||
val, pos = parse_expr(tokens, pos + 1)
|
||||
if pos >= len(tokens) or tokens[pos] != ')':
|
||||
raise ValueError("Fehlende schließende Klammer")
|
||||
return val, pos + 1
|
||||
raise ValueError(f"Unerwartetes Token: {tok}")
|
||||
|
||||
def parse_mul(tokens, pos):
|
||||
val, pos = parse_primary(tokens, pos)
|
||||
while pos < len(tokens):
|
||||
tok = tokens[pos]
|
||||
if tok in ('*', '/'):
|
||||
right, pos = parse_primary(tokens, pos + 1)
|
||||
if tok == '*':
|
||||
val *= right
|
||||
else:
|
||||
if right == 0:
|
||||
raise ValueError("Division durch Null")
|
||||
val /= right
|
||||
else:
|
||||
break
|
||||
return val, pos
|
||||
|
||||
def parse_expr(tokens, pos):
|
||||
val, pos = parse_mul(tokens, pos)
|
||||
while pos < len(tokens):
|
||||
tok = tokens[pos]
|
||||
if tok in ('+', '-'):
|
||||
right, pos = parse_mul(tokens, pos + 1)
|
||||
if tok == '+':
|
||||
val += right
|
||||
else:
|
||||
val -= right
|
||||
else:
|
||||
break
|
||||
return val, pos
|
||||
|
||||
def berechne_formel(expr_str):
|
||||
if not expr_str or not expr_str.strip():
|
||||
return 0
|
||||
# Deutsche Dezimaltrenner ersetzen
|
||||
expr_str = expr_str.replace(',', '.')
|
||||
tokens = tokenize(expr_str.strip())
|
||||
if not tokens:
|
||||
return 0
|
||||
val, pos = parse_expr(tokens, 0)
|
||||
if pos != len(tokens):
|
||||
raise ValueError("Überflüssige Zeichen am Ende")
|
||||
return float(val)
|
||||
Reference in New Issue
Block a user