worked on errors

another_parse_input
a.jurcenko 2025-09-29 14:17:17 +02:00
parent d608d2f077
commit 595fae4a13
7 changed files with 340 additions and 45 deletions

View File

@ -0,0 +1,22 @@
import unittest
from abacus import Abacus
class AbacusTest(unittest.TestCase):
def setUp(self):
self.ab = Abacus()
self.ab.set_var('code with', 20)
def test_var_assignment(self):
input_string = 'funk=(5+5)/2'
input_string = Abacus.clean_input(input_string)
chunks = Abacus.split_chunks(input_string)
Abacus.validate_chunks(chunks)
comment = Abacus.get_comment_from_chunks(chunks)
chunks_wo_comment = Abacus.get_chunks_without_comment(chunks)
chunks_wo = self.ab.process_chunks(chunks_wo_comment)
var, chunks_wo_var = Abacus.get_var_assignment_from_chunks(chunks_wo_comment)
if var is not None:
res = Abacus.calculate(''.join(chunks_wo_var))
self.ab.set_var(var, res)

270
abacus.py 100644
View File

@ -0,0 +1,270 @@
import mathematik
class AbacusMultipleAssignmentException(Exception):
pass
class AbacusNameAssignmentException(Exception):
pass
class AbacusWrongAssignmentException(Exception):
pass
class AbacusEmptyAssignmentException(Exception):
pass
class AbacusDataModel:
step_no = 0
def __init__(self, input_string, chunks, chunks_values, value, comment, step_no=None):
self._input_string = input_string
self._chunks = chunks
self._chunks_values = chunks_values
self._value = value
self._comment = comment
if step_no is not None:
self._step_no = step_no
else:
self._step_no = AbacusDataModel._get_next_step_no()
@classmethod
def _get_next_step_no(cls):
cls.step_no += 1
return cls.step_no
@property
def value(self):
return self._value
@property
def input_string(self):
return self._input_string
@property
def chunks(self):
return self._chunks
@property
def chunks_values(self):
return self._chunks_values
@property
def comment(self):
return self._comment
def __repr__(self):
return self._step_no, self._input_string, str(self._chunks), str(self._chunks_values), self._value, self._comment
class Abacus:
stop_operators = [':', '=']
operators = ['+', '-', '*', '/', ',']
brackets = ['(', ')']
comment = '#'
math_operator = '>'
def __init__(self):
self._vars = {'result': '0', 'cba': 'result+20+add'}
self._formel = {'add': 'result+10', 'abc': 'cba-result'} # dict()
def get_vars(self):
return self._vars
def get_var_by_name(self, name):
return self._vars.get(name, None)
def get_formel_by_name(self, name):
return self._formel.get(name, None)
def set_var(self, name, value):
if name in Abacus.stop_operators or name in Abacus.operators or name in Abacus.comment or name in Abacus.brackets:
raise AbacusNameAssignmentException('Name cannot be a operator')
res = self.get_formel_by_name(name)
if res:
raise AbacusNameAssignmentException('Name {} already exists'.format(name))
self._vars[name] = str(value)
def set_formel(self, name, value):
if name in Abacus.stop_operators or name in Abacus.operators or name in Abacus.comment or name in Abacus.brackets:
raise AbacusNameAssignmentException('Name cannot be a operator')
res = self.get_var_by_name(name)
if res:
raise AbacusNameAssignmentException('Name {} already exists'.format(name))
self._formel[name] = str(value)
@classmethod
def calculate(cls, input_string):
try:
return eval(input_string)
except Exception as e:
return e
@classmethod
def clean_input(cls, input_string):
input_string = str(input_string)
# input_string = input_string.replace(' ', '')
# input_string = input_string.replace('.', '')
input_string = input_string.replace(',', '.')
input_string = input_string.replace(';', ',')
return input_string.strip()
@classmethod
def split_chunks(cls, input_string):
chunks = list()
last_pos = 0
cnt_stop = 0
for i, c in enumerate(input_string):
if c == cls.comment:
if last_pos != i:
chunks.append(input_string[last_pos:i].strip())
chunks.append(input_string[i:].strip())
return chunks
if c in cls.stop_operators and cnt_stop == 0:
chunks.append(input_string[last_pos:i].strip())
chunks.append(input_string[i])
last_pos = i+1
cnt_stop += 1
elif c in cls.stop_operators and cnt_stop > 0:
raise AbacusMultipleAssignmentException('Multiple assignments not supported')
if c in cls.operators or c in cls.brackets:
if i != last_pos:
chunks.append(input_string[last_pos:i].strip())
chunks.append(input_string[i].strip())
last_pos = i+1
elif i == len(input_string)-1: # das letzte zeichen
chunks.append(input_string[last_pos:i+1].strip())
return chunks
@classmethod
def validate_chunks(cls, chunks):
input_str = ''.join(chunks)
if input_str[-1] in cls.operators:
raise AbacusWrongAssignmentException('Last character cannot be a operator')
for i, chunk in enumerate(chunks):
if chunk in cls.stop_operators and i != 1:
raise AbacusWrongAssignmentException('Wrong assignment expression')
@classmethod
def replace_operator_to_math(cls, input_string):
return input_string.replace(cls.math_operator, 'mathematik.')
def process_chunks(self, chunks):
chunks = chunks[:]
for i, chunk in enumerate(chunks):
res = self.get_var_by_name(chunk)
if res is not None:
chunks[i] = res
else:
res = self.get_formel_by_name(chunk)
if res is not None:
cchunks = Abacus.split_chunks(res)
res_var = self.process_chunks(cchunks)
for i in res_var:
chunks.insert()[i] = res_var # TODO: Unboxing die Liste und integration in die bestehende
return chunks
def _replace_formel_and_vars(self, input_str):
chunks = Abacus.split_chunks(input_str)
for i, chunk in enumerate(chunks):
res = self.get_var_by_name(chunk)
if res is not None:
chunks[i] = self._replace_formel_and_vars(res)
else:
res = self.get_formel_by_name(chunk)
if res is not None:
chunks[i] = self._replace_formel_and_vars(res)
return ''.join(chunks)
def process_input(self, input_str):
input_string = Abacus.clean_input(input_str)
input_string = self.replace_operator_to_math(input_string)
if len(input_string) == 0:
raise AbacusEmptyAssignmentException('Empty assignment expression')
chunks = Abacus.split_chunks(input_string)
comment, chunks = Abacus.get_comment_and_rest(chunks)
Abacus.validate_chunks(chunks)
formel, var_chunks = Abacus.get_function_assignment_from_chunks(chunks)
if formel is not None:
self.set_formel(formel, ''.join(var_chunks))
clean_chunks = self._replace_formel_and_vars(''.join(var_chunks))
value = Abacus.calculate(clean_chunks)
return input_string, chunks, clean_chunks, value, comment
else:
var, formel_chunks = Abacus.get_var_assignment_from_chunks(chunks)
if var is not None:
self.set_var(var, ''.join(formel_chunks))
clean_chunks = self._replace_formel_and_vars(''.join(formel_chunks))
value = Abacus.calculate(clean_chunks)
return input_string, chunks, clean_chunks, value, comment
else:
clean_chunks = self._replace_formel_and_vars(''.join(chunks))
value = Abacus.calculate(clean_chunks)
return input_string, chunks, clean_chunks, value, comment
@classmethod
def get_var_assignment_from_chunks(cls, chunks):
chunks = chunks[:]
chunks = ''.join(chunks).split(cls.stop_operators[1])
if len(chunks) > 2:
raise AbacusMultipleAssignmentException('Multiple assignments not supported')
if len(chunks) == 2:
return chunks[0], chunks[1:]
return None, None
@classmethod
def get_function_assignment_from_chunks(cls, chunks):
chunks = chunks[:]
chunks = ''.join(chunks).split(cls.stop_operators[0])
if len(chunks) > 2:
raise AbacusMultipleAssignmentException('Multiple assignments not supported')
if len(chunks) == 2:
return chunks[0], chunks[1:]
return None, None
@classmethod
def get_comment_from_chunks(cls, chunks):
for chunk in chunks:
chunk = str(chunk)
if chunk.startswith(cls.comment):
chunk = chunk[1:]
return chunk.strip()
return None
@classmethod
def get_chunks_without_comment(cls, chunks):
for i, chunk in enumerate(chunks):
chunk = str(chunk)
if chunk.startswith(cls.comment):
return chunks[:i]
return chunks
@classmethod
def get_comment_and_rest(cls, chunks):
comment = cls.get_comment_from_chunks(chunks)
rest = cls.get_chunks_without_comment(chunks)
return comment, rest
if __name__ == '__main__':
input_string = ['10+5', 'bbc:(10+10)', 'bba=(bbc+20)', 'bba//bbc']
steps = list()
ab = Abacus()
for i_s in input_string:
res = ab.process_input(i_s)
adm = AbacusDataModel(*res)
steps.append(adm)
for s in steps:
s.__repr__()

View File

@ -4,7 +4,7 @@
class AbacusCore: class AbacusCore:
def __init__(self): def __init__(self):
self._input_string = input self._input_string = ""
self._vars = dict() self._vars = dict()
self._funcs = dict() self._funcs = dict()

30
gui.ui
View File

@ -15,6 +15,20 @@
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_5"> <layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="le_input"/>
</item>
<item>
<widget class="QPushButton" name="but_enter">
<property name="text">
<string>Rechne!</string>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_4"> <layout class="QHBoxLayout" name="horizontalLayout_4">
<item> <item>
@ -122,20 +136,6 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="le_input"/>
</item>
<item>
<widget class="QPushButton" name="but_enter">
<property name="text">
<string>Rechne!</string>
</property>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QMenuBar" name="menubar"> <widget class="QMenuBar" name="menubar">
@ -144,7 +144,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>735</width> <width>735</width>
<height>24</height> <height>33</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuDatei"> <widget class="QMenu" name="menuDatei">

47
main.py
View File

@ -4,15 +4,15 @@ from PySide6.QtGui import QStandardItemModel, QStandardItem
from PySide6.QtUiTools import QUiLoader from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QApplication, QFileDialog from PySide6.QtWidgets import QApplication, QFileDialog
from PySide6.QtCore import QFile, QIODevice, QModelIndex, QAbstractTableModel from PySide6.QtCore import QFile, QIODevice, QModelIndex, QAbstractTableModel
from abacus_core import AbacusCore from abacus import Abacus, AbacusDataModel, AbacusEmptyAssignmentException
class AbacusGUI: class AbacusGUI:
def __init__(self): def __init__(self):
self._abacus_core = AbacusCore() self._abacus = Abacus()
self._step = 0
self._history = [] self._history = []
self._app = QApplication(sys.argv) self._app = QApplication(sys.argv)
ui_file_name = "gui.ui" ui_file_name = "gui.ui"
ui_file = QFile(ui_file_name) ui_file = QFile(ui_file_name)
@ -34,33 +34,26 @@ class AbacusGUI:
self._func_model = QStandardItemModel() self._func_model = QStandardItemModel()
self._window.lv_variable.setModel(self._var_model) self._window.lv_variable.setModel(self._var_model)
self._window.lv_func.setModel(self._func_model) self._window.lv_func.setModel(self._func_model)
# self._window.actionExit.clicked.connect(self._berechne)
self._check_models() self._check_models()
sys.exit(self._app.exec()) sys.exit(self._app.exec())
def _berechne(self): def _berechne(self):
input_str = self._window.le_input.text() input_str = self._window.le_input.text()
result = self._abacus_core.parse_input(input_str) try:
self._abacus.process_input(input_str)
except AbacusEmptyAssignmentException as e:
print(e)
return
result = self._abacus.process_input(input_str)
if result: if result:
adm = AbacusDataModel(*result)
self._history.append(adm)
self._history.append(result) self._history.append(result)
input_str = result[0] # item = QStandardItem('Halllo')
input_wo_var = str(result[1]) item = QStandardItem(str(result))
ergebnis = str(result[2]) self._history_model.appendRow(item)
comment = result[3] self._abacus.set_var('result', result[3])
if result[0] is not None: self._window.le_input.setText(str(result[3]))
self._step += 1
res_str = str(self._step) + '> ' + input_str + ' = ' + ergebnis
# res_str = str(self._step) + '. ' + input_str + ' => ' + input_wo_var + ' = ' + ergebnis
if comment:
res_str += ' ' + comment
item = QStandardItem(res_str)
self._history_model.appendRow(item)
res = result[2]
self._window.le_input.setText(str(res))
elif result[3] is not None:
item = QStandardItem(comment)
self._history_model.appendRow(item)
self._window.le_input.setText('')
else: else:
self._window.le_input.setText('') self._window.le_input.setText('')
self._check_models() self._check_models()
@ -68,12 +61,12 @@ class AbacusGUI:
def _check_models(self): def _check_models(self):
self._var_model.clear() self._var_model.clear()
self._func_model.clear() self._func_model.clear()
for k, v in self._abacus_core.get_vars().items(): for k, v in self._abacus.get_vars().items():
item = QStandardItem(k+' = '+str(v)) item = QStandardItem(k+' = '+str(v))
self._var_model.appendRow(item) self._var_model.appendRow(item)
for k, v in self._abacus_core.get_funcs().items(): # for k, v in self._abacus_core.get_funcs().items():
item = QStandardItem(k+' = '+str(v)) # item = QStandardItem(k+' = '+str(v))
self._func_model.appendRow(item) # self._func_model.appendRow(item)
if __name__ == "__main__": if __name__ == "__main__":

11
mathematik.py 100644
View File

@ -0,0 +1,11 @@
import math
def runden(number, ndigits=None):
return round(number, ndigits)
def potenz(x, y):
return math.pow(x,y)
def prozent_von(number, von):
return von / 100 * number

View File

@ -3,5 +3,4 @@
## Sinn und Zweck ## Sinn und Zweck
## Known Bugs ## Known Bugs
- Eine ein-zeichen Variable so wie _ oder a funktioniert nicht -
- rückgabewert einer funktion lässt sich nicht einer variablen zuweisen