From 595fae4a13c09ad10d9c3e9882417b28da575539 Mon Sep 17 00:00:00 2001 From: "a.jurcenko" Date: Mon, 29 Sep 2025 14:17:17 +0200 Subject: [PATCH] worked on errors --- Tests/test_abacus.py | 22 ++++ abacus.py | 270 +++++++++++++++++++++++++++++++++++++++++++ abacus_core.py | 2 +- gui.ui | 30 ++--- main.py | 47 ++++---- mathematik.py | 11 ++ readme.md | 3 +- 7 files changed, 340 insertions(+), 45 deletions(-) create mode 100644 Tests/test_abacus.py create mode 100644 abacus.py create mode 100644 mathematik.py diff --git a/Tests/test_abacus.py b/Tests/test_abacus.py new file mode 100644 index 0000000..cfd9a45 --- /dev/null +++ b/Tests/test_abacus.py @@ -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) \ No newline at end of file diff --git a/abacus.py b/abacus.py new file mode 100644 index 0000000..8d06db8 --- /dev/null +++ b/abacus.py @@ -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__() + diff --git a/abacus_core.py b/abacus_core.py index ae2a203..bdbfcf8 100644 --- a/abacus_core.py +++ b/abacus_core.py @@ -4,7 +4,7 @@ class AbacusCore: def __init__(self): - self._input_string = input + self._input_string = "" self._vars = dict() self._funcs = dict() diff --git a/gui.ui b/gui.ui index 01420fb..d8ac188 100644 --- a/gui.ui +++ b/gui.ui @@ -15,6 +15,20 @@ + + + + + + + + + Rechne! + + + + + @@ -122,20 +136,6 @@ - - - - - - - - - Rechne! - - - - - @@ -144,7 +144,7 @@ 0 0 735 - 24 + 33 diff --git a/main.py b/main.py index e0a6cbb..3a7998c 100644 --- a/main.py +++ b/main.py @@ -4,15 +4,15 @@ from PySide6.QtGui import QStandardItemModel, QStandardItem from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QApplication, QFileDialog from PySide6.QtCore import QFile, QIODevice, QModelIndex, QAbstractTableModel -from abacus_core import AbacusCore +from abacus import Abacus, AbacusDataModel, AbacusEmptyAssignmentException class AbacusGUI: def __init__(self): - self._abacus_core = AbacusCore() - self._step = 0 + self._abacus = Abacus() self._history = [] + self._app = QApplication(sys.argv) ui_file_name = "gui.ui" ui_file = QFile(ui_file_name) @@ -34,33 +34,26 @@ class AbacusGUI: self._func_model = QStandardItemModel() self._window.lv_variable.setModel(self._var_model) self._window.lv_func.setModel(self._func_model) - # self._window.actionExit.clicked.connect(self._berechne) self._check_models() sys.exit(self._app.exec()) def _berechne(self): 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: + adm = AbacusDataModel(*result) + self._history.append(adm) self._history.append(result) - input_str = result[0] - input_wo_var = str(result[1]) - ergebnis = str(result[2]) - comment = result[3] - if result[0] is not None: - 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('') + # item = QStandardItem('Halllo') + item = QStandardItem(str(result)) + self._history_model.appendRow(item) + self._abacus.set_var('result', result[3]) + self._window.le_input.setText(str(result[3])) else: self._window.le_input.setText('') self._check_models() @@ -68,12 +61,12 @@ class AbacusGUI: def _check_models(self): self._var_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)) self._var_model.appendRow(item) - for k, v in self._abacus_core.get_funcs().items(): - item = QStandardItem(k+' = '+str(v)) - self._func_model.appendRow(item) + # for k, v in self._abacus_core.get_funcs().items(): + # item = QStandardItem(k+' = '+str(v)) + # self._func_model.appendRow(item) if __name__ == "__main__": diff --git a/mathematik.py b/mathematik.py new file mode 100644 index 0000000..1ddaf3b --- /dev/null +++ b/mathematik.py @@ -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 diff --git a/readme.md b/readme.md index b563ba7..1a2ae6e 100644 --- a/readme.md +++ b/readme.md @@ -3,5 +3,4 @@ ## Sinn und Zweck ## Known Bugs -- Eine ein-zeichen Variable so wie _ oder a funktioniert nicht -- rückgabewert einer funktion lässt sich nicht einer variablen zuweisen +-