Ich habe eine Zeichenfolge, die eine mathematische Gleichung ist, aber mit einigen benutzerdefinierten Funktionen. Ich muss alle diese Funktionen finden und durch Code ersetzen.
Zum Beispiel habe ich eine Zeichenfolge:
%Vor% Ich möchte Code, der (zB) f2(x,y)
durch x+y^2
und f1(x,y)
durch sin(x+y)
Es wäre ideal, wenn verschachtelte Funktionen wie im Beispiel unterstützt würden. Es wäre jedoch immer noch nützlich, wenn die Verschachtelung nicht unterstützt wird.
Wie ich aus ähnlichen Themen verstehe, kann dies mit einem Compiler-Modul wie compiler.parse(eq)
geschehen. Kann mir jemand erklären, wie ich mit AST-Objekt arbeiten kann, das von compiler.parse(eq)
erstellt wurde, um meinen String zurück zu rekonstruieren und alle gefundenen Funktionen zu ersetzen?
Ich muss nur die Substitution durchführen und dann wird die Zeichenfolge in einem anderen Programm verwendet. Bewertung nicht erforderlich.
ein minimales Arbeitsbeispiel ( +,-,*,/,**
binary und unäre Operationen und Funktionsaufruf implementiert) Die Priorität der Operation wird mit Klammern
ein bisschen mehr als die Funktionalität für das gegebene Beispiel ist
gemacht %Vor%Verwendung:
%Vor%Ergebnis
%Vor%WARNUNG Der Code arbeitet mit python2.7 und es ist nicht möglich mit anderen Versionen von Python zu arbeiten. Die Python 3-Version funktioniert nicht
Die vollständige Ersetzung ist ziemlich schwierig. Hier ist mein Versuch, es zu tun. Hier können wir erfolgreich Ausdrücke einbinden,
aber nicht in allen Szenarien. Dieser Code funktioniert nur mit AST, erstellt von ast
module. Und verwendet codegen
, um es zurück zum Code zu stringieren. Das Stringing von ast und modifizierendem ast im Allgemeinen wird in anderen SO Q / A behandelt: "Analysiere eine .py-Datei, lese den AST, modifiziere ihn und schreibe den modifizierten Quellcode zurück" .
Zuerst definieren wir wenige Helfer:
%Vor% Danach definieren wir eine Substitutionsfunktion mit NodeTransformer
.
Zum Beispiel:
Die simultane Substitution mehrerer Variablen ist erforderlich, um unangenehme Situationen richtig zu vermeiden.
Zum Beispiel ersetzen Sie sowohl a
als auch b
für a + b
in a + b
.
Das Ergebnis sollte (a + b) + (a + b)
sein, aber wenn wir zuerst a
für a + b
ersetzen, erhalten wir (a + b) + b
und dann b
, wir erhalten (a + (a + b)) + b
, was das falsche Ergebnis ist! Also simultan ist wichtig:
Dann schreiben wir ähnlich NodeTransformer
, um Aufrufe zu finden, wo wir Inline-Funktionsdefinitionen :
Das substituteCalls
ist rekursiv, sodass wir auch rekursive Inline-Funktionen verwenden können. Außerdem gibt es eine explizite Grenze, da einige Definitionen unendlich rekursiv sein können (als fact
unten). Es gibt ein bisschen hässlich aussehende kopieren, aber es ist erforderlich, verschiedene Unterbäume zu trennen.
Und der Beispielcode:
%Vor%Was ausdruckt:
%Vor% Leider codegen
version in pypi
ist fehlerhaft. Ausdrücke werden nicht richtig in Klammern gesetzt, selbst AST sagt, sie sollten es tun. Ich habe jbremer / codegen ( pip install git+git://github.com/jbremer/codegen
) verwendet. Es fügt auch unnötige Klammern hinzu, aber es ist besser als gar keine. Danke an @XavierCombelle für den Tipp.
Die Substitution wird komplizierter, wenn Sie anonyme Funktionen haben, d. h. lambda
. Dann müssen Sie Variablen umbenennen. Sie könnten versuchen, nach Lambda-Kalkül mit Substitution oder Implementierung zu suchen. Dennoch hatte ich Pech, irgendwelche Artikel zu finden, die Python für diese Aufgabe verwenden.
kennen Sie die Variablen im Voraus?
Ich empfehle die Verwendung von sympy!
nehmen Sie zum Beispiel Folgendes:
%Vor% 'z' ist jetzt ein symbolischer Ausdruck, der die mathematische Formel darstellt. Sie können es ausdrucken. Sie können dann subs
verwenden, um symbolische Ausdrücke oder Funktionen zu ersetzen. Sie können entweder sine symbolisch wieder darstellen (wie f1
und f2
) oder Sie können möglicherweise die sin()
in sympy.mpmath
Je nach Ihren Bedürfnissen ist dieser Ansatz großartig, da Sie diesen Ausdruck eventuell berechnen, bewerten oder vereinfachen können.
hoffe das hilft!
(Verwendung von sympy
als adrianX wurde vorgeschlagen, mit zusätzlichem Code.)
Der folgende Code konvertiert eine gegebene Zeichenfolge in eine neue Zeichenfolge, nachdem bestimmte Funktionen kombiniert wurden. Es ist hastig und schlecht dokumentiert, aber es funktioniert .
WARNUNG!
Enthält exec
eval
, bösartiger Code könnte wahrscheinlich eine Auswirkung haben, wenn die Eingabe von externen Benutzern bereitgestellt wird.
UPDATE:
Was ist Ihr langfristiges Ziel? Soll die Funktion bewertet oder einfach substituiert werden? Im ersten Fall können Sie dies einfach ausprobieren (beachten Sie, dass f1
und f2
auch dynamisch definiert werden können):
Wenn Sie die Funktionen ersetzen und die modifizierte Version zurückbekommen wollen, müssen Sie tatsächlich auf einen AST-Parser zurückgreifen. Seien Sie jedoch vorsichtig bei der Verwendung von eval
, da dies eine Sicherheitslücke für bösartigen Benutzereingabecode öffnet.
Ich denke, Sie möchten etwas wie PyBison
verwenden, das ein Parser-Generator ist.
Sehen Sie sich ein Beispiel an, das den hier benötigten Basiscode enthält:
Sie müssen einen Tokentyp für Funktionen und eine Regel für Funktionen hinzufügen und dann, was mit dieser Funktion passiert, wenn sie gefunden wird.
Wenn Sie weitere Informationen zum Parsen usw. benötigen, versuchen Sie einige grundlegende Tutorials zu Lex und (Yacc oder Bison) zu lesen.
Tags und Links python parsing python-2.7 equation