Berechnung mit Input

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Expanse
User
Beiträge: 9
Registriert: Samstag 2. Januar 2021, 01:43

Samstag 2. Januar 2021, 01:57

Hallo,

ich würde gerne durch eine Eingabe des Nutzer eine Berechnung durchführen. Allerdings sollte die Eingabe durch Variablen erfolgen. In einer Liste oder Dictionary sollen die Variablen mit den entsprechenden Werten abgespeichert sein.
Ein einfaches Beispiel:

Code: Alles auswählen

A, B, C = 1, 2, 3
liste = [A, B, C]
dictionary = {'A': 1, 'B': 2, 'C': 3)

result = input('Berechung: ')
print(result)
Leider habe ich bisher noch keinen guten Ansatz gefunden. Mit eval() habe ich es auch versucht, nur konnte ich dies nicht mit den Variablen verbinden.

Ich bedanke mich vorab.

Viele Grüße
Michael
__deets__
User
Beiträge: 9882
Registriert: Mittwoch 14. Oktober 2015, 14:29

Samstag 2. Januar 2021, 11:16

Ich habe keine Idee, was du da vorhast. Kannst du mal ein Beispiel deiner Eingabe angeben?
Benutzeravatar
pillmuncher
User
Beiträge: 1267
Registriert: Samstag 21. März 2009, 22:59
Wohnort: München

Samstag 2. Januar 2021, 12:10

eval() würde ich nicht verwenden, weil die Benutzer da alles Mögliche eingeben (und ausführen!) können, um auf deinem Rechner Schaden anzurichten.
Statt dessen benutze entweder ast.literal_eval() oder bau dir einen einfachen Interpreter für arithmetische Formeln. Zum Beispiel nach dieser Anleitung: https://www.booleanworld.com/building-r ... n_grammars
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
pillmuncher
User
Beiträge: 1267
Registriert: Samstag 21. März 2009, 22:59
Wohnort: München

Samstag 2. Januar 2021, 12:41

Just for funsies:

Code: Alles auswählen

from __future__ import print_function
from parcon import number, id_word, InfixExpr, Forward
from operator import add, sub, mul, truediv, neg


class Universe(dict):

    def __init__(self, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)
        formula = Forward()
        term = (
            number[lambda value: float(value) if '.' in value else int(value)]
            | id_word[self.__getitem__]
            | '-' + formula[neg]
            | '(' + formula + ')'
        )
        term = InfixExpr(term, [('*', mul), ('/', truediv)])
        term = InfixExpr(term, [('+', add), ('-', sub)])
        formula << term
        self.evaluate = formula.parse_string


def main():
    solver = Universe(a=2, b=3, c=5)
    print(solver.evaluate('a'))
    print(solver.evaluate('b'))
    print(solver.evaluate('c'))
    print(solver.evaluate('123'))
    print(solver.evaluate('123.45 * a + b'))
    print(solver.evaluate('123.45 * (a + b) * -c'))


if __name__ == '__main__':
    main()
Ergebnis:

Code: Alles auswählen

2
3
5
123
249.9
-3086.25
Geht leider nur mit Python 2.7, weil Parcon da scheinbar stehengeblieben ist.
In specifications, Murphy's Law supersedes Ohm's.
Expanse
User
Beiträge: 9
Registriert: Samstag 2. Januar 2021, 01:43

Samstag 2. Januar 2021, 15:31

Vielen Dank für die Antwort.
Leider kann ich Pardon nicht benutzen, ich arbeite mit Python 3.9. Trotzdem sehr guter Ansatz, wird mir sehr hilfreich sein.

Um nochmals mein Problem etwas genauer zu schildern:
Der User soll bspw. durch die Eingabe (Input) von

Code: Alles auswählen

A + B
das Ergebnis 3 erhalten. Genauso auch Sub, Mul, Div Rechnungen tätigen können.
__deets__
User
Beiträge: 9882
Registriert: Mittwoch 14. Oktober 2015, 14:29

Samstag 2. Januar 2021, 15:34

pillmuncher hat ja auch ein paar andere Ansaetze genannt. Probier die aus.
Benutzeravatar
__blackjack__
User
Beiträge: 8721
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Samstag 2. Januar 2021, 16:03

@Expanse: `parcon` ist nicht das einzige Projekt seiner Art. Recht verbreitet und noch aktiv weiterentwickelt wird beispielsweise PyParser.
long long ago; /* in a galaxy far far away */
Expanse
User
Beiträge: 9
Registriert: Samstag 2. Januar 2021, 01:43

Samstag 2. Januar 2021, 16:49

Ok, ich bin noch nicht weit fortgeschritten in Python. Aber gibt es keine einfache Möglichkeit dass der User auf die Dictionary zugreifen kann.

Code: Alles auswählen

D = {'A': 1, 'B': 2, 'C': 3)

eingabe = input('Berechung: ')

if eingabe in D:
	print(D[eingabe])
nun wollte ich mit elif die Operators definieren, um Berechnungen durchführen zu können, wie A + B oder A + B - C

Code: Alles auswählen

elif '+' in eingabe:
	pass
elif '-' in eingabe:
	pass
...
Vielen Danke vorab für eure Hilfe!

Gruß
Michael
Benutzeravatar
__blackjack__
User
Beiträge: 8721
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Samstag 2. Januar 2021, 17:30

@Expanse: Wie sollen denn die Eingaben genau aussehen? Wir sind ja bisher davon ausgegangen, dass da beliebige Ausdrücke mit den Operatoren "+", "-", "*", und "/" stehen dürfen und das Punkt- vor Strichrechnung gilt. Vielleicht solltest Du erst einmal *genau* spezifizieren was das Programm am Ende können soll. Inklusive was passieren soll wenn der Benutzer etwas falsches eingibt.

So wie Du Dir das mit ``if`` und ``relif`` gedacht hast, wird das sicher nicht funktionieren, denn wenn der Benutzer "A + B" eingibt, dann ist das nicht im Wörterbuch und "+" wäre auch in "+" enthalten, oder in "+AB" oder "AB+".
long long ago; /* in a galaxy far far away */
Expanse
User
Beiträge: 9
Registriert: Samstag 2. Januar 2021, 01:43

Samstag 2. Januar 2021, 18:14

Das Problem ist eigentlich, dass ich eine Sammlung von Variablen habe, mit denen ich Rechenoperationen durchführen lassen will (durch den User).

Die Variablen (A, B, C ... G) sind float-Werte (+ und - ) und sollen entweder in einer Liste oder Dictionary aufgelistet sein. Bisher bin ich mit Dictionary besser voran gekommen.

Die Rechenoperationen sollen einfachste Rechnungen sein: Add und Sub. Mul und Div wären Zusatz und kein Muss, in meinem Fall. Genauso auch mathematische Regeln wie Minus-Klammer kein muss.
__deets__
User
Beiträge: 9882
Registriert: Mittwoch 14. Oktober 2015, 14:29

Samstag 2. Januar 2021, 18:45

Du musst dir eben einen parser schreiben. Wenn weder Klammern noch andere Operatoren ausser + und - vorkommen, ist das ja trivial: du tokenisierst die Eingabe, und gehst die von links nach rechts durch. Am Anfang ist das Ergebnis 0, die erste Variable setzt es dann auf den Wert der Variablen, dann kommt ein Operator, den du dir merkst, und dann kommt die naechste Variable, und zusammen mit dem Operator berechnest du das neue Ergebnis. Etc.
Expanse
User
Beiträge: 9
Registriert: Samstag 2. Januar 2021, 01:43

Samstag 2. Januar 2021, 20:22

Ja genau, so habe ich es anfangs auch gemacht. Allerdings soll jede Berechnung mit einer einzigen Eingabe erfolgen (also in einer Zeile).
Also: A + B + C
und nicht als getrennte Inputs:
A
+
B
+
C

Gibt es hierzu auch eine Möglichkeit? Mit der split() Funktion habe ich auch versucht. Bin damit aber auch nicht weitergekommen
__deets__
User
Beiträge: 9882
Registriert: Mittwoch 14. Oktober 2015, 14:29

Samstag 2. Januar 2021, 20:37

Das ist doch nahezu das Gleiche. Selbstverstaendlich kannst u auch in einer Zeile

A + B

oder auch

A+B

eingeben.

Da du nicht kontrollieren kannst, ob deine Benutzer wirklich Leerzeichen eingeben, reicht split eben nicht.

Stattdessen musst du eben zeichenweise ueber die Eingabe laufen, und pruefen was es ist:

- ein Buchstabe aus deiner Variablenmenge -> Wert behandeln
- ein Operator -> Operation merken
- ein Leerzeichen -> ignorieren
- irgendwas anderes: Fehler ausgeben.
Expanse
User
Beiträge: 9
Registriert: Samstag 2. Januar 2021, 01:43

Samstag 2. Januar 2021, 21:05

Ja, aber input ist mit einer For-Schleife der Länge einer bestimmten Liste verknüpft. Der User soll dementsprechend die Variablen bzw. Variablenberechnungen eingeben können und die Ergebnisse sollen wiederum in einer Liste abgespeichert werden. Deswegen müsste jede Berechnung in einer Zeile erfolgen
Benutzeravatar
__blackjack__
User
Beiträge: 8721
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Samstag 2. Januar 2021, 21:09

@Expanse: Ich verstehe nicht so recht was Du uns damit sagen willst. __deets__ hat beschrieben wie man für eine Rechnung vorgehen muss. Wenn Du das hast, kannst Du das ja ganz einfach für jede Zeile aufrufen.
long long ago; /* in a galaxy far far away */
Antworten