Compare commits

..

No commits in common. "another_parse_input" and "master" have entirely different histories.

8 changed files with 71 additions and 744 deletions

View File

@ -1,22 +0,0 @@
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
View File

@ -1,270 +0,0 @@
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,178 +4,95 @@
class AbacusCore:
def __init__(self):
self._input_string = ""
self._input_string = input
self._vars = dict()
self._funcs = dict()
self._vars['result'] = 0
self._vars['alphabet'] = 28
self._vars['alpha'] = 1
self._vars['beta'] = 2
self._operators = ['+', '-', '/', '*']
self._delimiters = ['(', ')', '[', ']', ';', ' ']
self._funcs['r2'] = lambda x: round(x, 2)
self._funcs['r0'] = lambda x: int(x)
def get_vars(self):
return self._vars
def get_funcs(self):
return self._funcs
def add_var(self, name, value):
self._vars[name] = value
def _calculate(self, input_str):
print('input:', input_str)
try:
return eval(input_str)
return True, eval(input_str)
except ZeroDivisionError:
res = 'Division by Zero'
except NameError as e:
res = 'Variable '+ e.name + ' not exists'
except SyntaxError as e:
res = 'Syntax Error'
return res
return False, res
def get_vars(self):
return self._vars
def add_var(self, name, value):
self._vars[name] = value
def parse_input(self, input_str):
'''
versuche input_str zu parsen in comment vars und andere teile
:param input_str:
:return:
'''
input_str = input_str.strip()
comment = None
orig_input_str = input_str
if len(input_str) < 1: # leere eingabe wird nicht akzeptiert
return
if input_str[0] == '#': # ganze eingabe ist ein kommentar
comment = input_str
return None, None, None, comment
chunks = input_str.split('#')
if len(chunks) > 1:
input_str = chunks[0]
comment = ' '.join(chunks[1:])
chunks = input_str.split('=') # gibt es variablenzuweisung?
if len(chunks) > 2:
raise ValueError('Mehrfachzuweisung wird nicht unterstützt')
elif len(chunks) > 1:
expression = self._with_variable_another_way(chunks[1])
chunks[0] = '_'.join(chunks[0].strip().split(' '))
self._vars[chunks[0]] = expression
return
chunks = input_str.split(':') # gibt es funktionsdefinition?
if len(chunks) > 1:
self._funcs[chunks[0]] = chunks[1]
return
res = self._with_variable_another_way(input_str)
self._vars['result'] = res
return orig_input_str, None, res, comment
def _with_variable_another_way(self, input_str):
input_str, comment = self._get_input_wo_commentar(input_str)
input_str = ''.join(input_str.split()) # entferne alle leerzeichen
input_wo_com = None
success = False
input_str = str(input_str).strip()
input_str = input_str.replace(',', '.')
opdel = self._operators + self._delimiters
chunks = list()
last_index = 0
for i, v in enumerate(input_str):
if v in opdel:
chunk = input_str[last_index:i]
chunk = self._is_a_variable_or_func(chunk)
chunks.append(chunk)
chunks.append(input_str[i])
last_index = i+1
elif i == len(input_str)-1:
chunk = input_str[last_index:i+1]
chunk = self._is_a_variable_or_func(chunk)
chunks.append(chunk)
return eval(''.join(chunks))
def _is_a_variable_or_func(self, chunk):
var = self._vars.get(chunk)
if not var:
var = self._funcs.get(chunk)
if var:
var = self._with_variable_another_way(var)
if var:
return str(var)
if input_str[0] == '#':
comment = input_str[1:]
com_index = input_str.find('#')
if com_index > -1:
input_wo_com = input_str[:com_index]
comment = input_str[com_index + 1:]
if input_wo_com is None:
input_wo_com = input_str
print('comment', comment)
result = self._split_input(input_wo_com)
print('result:',result)
if result[1] is not None:
success, res = self._calculate(result[1])
if success:
operators = result[0]
operators.reverse()
for op in operators:
if op[-1] == '=':
self._vars[op[:-1]] = res
elif op[-1] == ':':
res = self._funcs.get(op[:-1])(res)
print('vars:', self._vars)
else:
return chunk
print("Error")
def _replace_vars(self, input_str):
'''
try to find vars and replace them
:param input_str:
:return:
'''
first_position = None
new_input_str = ''
op_del = self._operators + self._delimiters
if input_str[0] in self._operators:
input_str = 'result' + input_str
input_str_len = len(input_str)
def _split_input(self, input_str):
last_position = 0
varchunks = list()
for i, c in enumerate(input_str):
if c in op_del or i == input_str_len-1: # and first_position is not None:
if first_position is not None:
last_position = i
if i == input_str_len-1:
last_position += 1
temp_var = input_str[first_position:last_position]
print('var', temp_var)
var = self._vars.get(temp_var)
if var is not None:
new_input_str += str(var)
else:
func = self._funcs.get(temp_var)
if func:
new_input_str += str(func)
else:
raise NotImplemented()
first_position = None
if i == input_str_len - 1:
continue
new_input_str += input_str[i]
elif c.isalpha() or c=='_':
if first_position is None:
first_position = i
else:
new_input_str += input_str[i]
return new_input_str
if c in [':', '=']:
chunk = input_str[last_position:i].strip()
chunk = chunk + input_str[i]
varchunks.append(chunk)
last_position = i+1
rest = input_str[last_position:].strip()
print('rest', rest)
rest = self._find_vars(rest)[1]
return varchunks, rest
def _get_input_wo_commentar(self, input_str):
'''
Zerlege input in input und kommentar
:param input_str:
:return:
'''
input_str = input_str.strip()
comment_index = input_str.find('#')
if comment_index == 0: # die ganze zeile ist ein kommentar
return None, input_str
elif comment_index == -1:
return input_str, None
else:
comment = input_str[comment_index + 1:]
input_str = input_str[:comment_index]
return input_str, comment
def _find_vars(self, input_str):
chunks = list()
last_position = 0
for i, c in enumerate(input_str):
if c in ['+', '-', '/', '*', '(', ')', '[', ']', ';']:
ch = input_str[last_position:i].strip()
if len(ch)>0:
chunks.append(ch)
chunks.append(input_str[i].strip())
last_position = i+1
def _is_new_variable(self, input_str):
'''
'''
chunks = input_str.split('=')
chunks_len = len(chunks)
if chunks_len > 2:
raise ValueError()
# chunks.reverse()
elif chunks_len == 2:
return chunks[1], chunks[0]
else:
return chunks[0], None
if last_position<len(input_str):
chunks.append(input_str[last_position:].strip())
cp_chunks = chunks.copy()
for i, chunk in enumerate(chunks):
if chunk in self._vars:
cp_chunks[i] = str(self._vars.get(chunk))
print(chunks, cp_chunks)
return len(cp_chunks)>1, ''.join(cp_chunks)

View File

@ -1,20 +0,0 @@
from abacus_core import AbacusCore
ab = AbacusCore()
if __name__ == '__main__':
step = 0
res = 0
while True:
var = input('gib was ein:')
if var == 'vars':
print(ab.get_vars())
elif var == 'func':
print(ab.get_funcs())
elif var == 'res':
print(res)
else:
step += 1
res = ab.parse_input(str(var))
print('step', step, 'result', res)

194
gui.ui
View File

@ -1,194 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>735</width>
<height>770</height>
</rect>
</property>
<property name="windowTitle">
<string>AbacusNG</string>
</property>
<widget class="QWidget" name="centralwidget">
<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>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Verlauf</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="lv_history"/>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Variablen</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QListView" name="lv_variable">
<property name="selectionMode">
<enum>QAbstractItemView::SelectionMode::SingleSelection</enum>
</property>
<property name="resizeMode">
<enum>QListView::ResizeMode::Adjust</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="but_var_new">
<property name="text">
<string>Neu</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="but_var_edit">
<property name="text">
<string>Bearbeiten</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="but_var_remove">
<property name="text">
<string>Löschen</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Funktionen</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListView" name="lv_func"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="but_func_new">
<property name="text">
<string>Neu</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="but_func_edit">
<property name="text">
<string>Bearbeiten</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="but_func_remove">
<property name="text">
<string>Löschnen</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>735</width>
<height>33</height>
</rect>
</property>
<widget class="QMenu" name="menuDatei">
<property name="title">
<string>Datei</string>
</property>
<addaction name="actionNeu"/>
<addaction name="separator"/>
<addaction name="actionSpeichern"/>
<addaction name="actionSpeichern_unter"/>
<addaction name="separator"/>
<addaction name="actionDrucken"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
<addaction name="menuDatei"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionNeu">
<property name="text">
<string>Neu</string>
</property>
</action>
<action name="actionSpeichern">
<property name="text">
<string>Speichern</string>
</property>
</action>
<action name="actionSpeichern_unter">
<property name="text">
<string>Speichern unter</string>
</property>
</action>
<action name="actionDrucken">
<property name="text">
<string>Drucken</string>
</property>
</action>
<action name="actionExit">
<property name="text">
<string>Beenden</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

75
main.py
View File

@ -1,74 +1,7 @@
import sys
from abacus_core import AbacusCore
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 import Abacus, AbacusDataModel, AbacusEmptyAssignmentException
ab = AbacusCore()
class AbacusGUI:
def __init__(self):
self._abacus = Abacus()
self._history = []
self._app = QApplication(sys.argv)
ui_file_name = "gui.ui"
ui_file = QFile(ui_file_name)
if not ui_file.open(QIODevice.ReadOnly):
print(f"Cannot open {ui_file_name}: {ui_file.errorString()}")
sys.exit(-1)
loader = QUiLoader()
self._window = loader.load(ui_file)
ui_file.close()
if not self._window:
print(loader.errorString())
sys.exit(-1)
self._window.show()
self._window.but_enter.clicked.connect(self._berechne)
self._window.le_input.returnPressed.connect(self._berechne)
self._history_model = QStandardItemModel()
self._window.lv_history.setModel(self._history_model)
self._var_model = QStandardItemModel()
self._func_model = QStandardItemModel()
self._window.lv_variable.setModel(self._var_model)
self._window.lv_func.setModel(self._func_model)
self._check_models()
sys.exit(self._app.exec())
def _berechne(self):
input_str = self._window.le_input.text()
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)
# 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()
def _check_models(self):
self._var_model.clear()
self._func_model.clear()
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)
if __name__ == "__main__":
ag = AbacusGUI()
if __name__ == '__main__':
ab.parse_input('12')

View File

@ -1,11 +0,0 @@
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

@ -1,6 +0,0 @@
# AbacusNG
## Sinn und Zweck
## Known Bugs
-