worked on errors
parent
d608d2f077
commit
595fae4a13
|
|
@ -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)
|
||||||
|
|
@ -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__()
|
||||||
|
|
||||||
|
|
@ -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
30
gui.ui
|
|
@ -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
47
main.py
|
|
@ -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__":
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue