Ich suche nach einer Java-Bibliothek, die mathematische Formeln in einen AST (abstrakten Syntaxbaum) zerlegen kann.
UPDATE:
Ich bin offen für Alternativen in anderen Sprachen als Java, vorausgesetzt, ich kann diese Tools/Bibliotheken von Java aus aufrufen.
Beispielsweise kann JavaScript mithilfe der Rhino-Engine eingebettet werden .
Essentielle Anforderungen:
Die Fähigkeit , Formeln in Infix - Notation zu analysieren .
Die Fähigkeit, unbekannte Variablen zu erhalten – ich suche keinen Taschenrechner.
Eine anpassbare Liste von Operatoren und Funktionen.
Es wäre auch hervorragend, wenn man bereits eingebaute Funktionen (zB sin(x)
) entfernen könnte.
Nicht wesentliche Anforderungen:
„Math.js ist eine umfangreiche Mathematikbibliothek für JavaScript und Node.js.“
— Projekt-Readme
Es bietet eine parse()- Funktion.
Beispiel mit der NodeJS-Umgebung:
var math = require('mathjs')();
var ast = math.parse('xy^(1/2)');
// Fully log the object
var util = require('util');
console.log(util.inspect(ast, {showHidden: false, depth: null}));
Ausgabe:
{ op: '^',
fn: 'pow',
params:
[ { name: 'xy' },
{ op: '/',
fn: 'divide',
params:
[ { valueType: 'number', value: '1' },
{ valueType: 'number', value: '2' } ] } ] }
Ich verwende die Java Nashorn VM (nur verfügbar in Java >= 8), um JavaScript auszuführen.
Programmarchitektur:
User ---------------> Java
inputs formla |----> Nashorn ----> math.js
|<---------------------|
User <-----------------|
Die Verwendung der Nashorn-Engine ist recht einfach (Ausnahmebehandlung weggelassen)
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(readerInstancePointingToMathJsLibrary);
engine.eval(readerInstancePointingToBridgeJavaScript);
Der JavaScript-Code der Bridge hängt stark von Ihrer Implementierung von AST-Knoten ab. Wir nutzen die Fähigkeit von Nashorn, Java-Objekte in JavaScript zu erstellen und nach Java zu übertragen. Beispiel:
var math = mathjs();
function convert(formula) {
var ast = math.parse(formula);
var javaAst = /* build your AST with Java objects */
return javaAst;
}
Wir können jetzt von Java aus auf diese Funktion zugreifen und sogar beliebige Argumente übergeben:
Invocable inv = (Invocable) engine;
// Expression is my AST node type in Java
expr = (Expression) inv.invokeFunction("convert", formulaFromUser);
Hinweis: Ich brauchte eine schnelle Möglichkeit, mathematische Ausdrücke zu analysieren. Ein Parser (entweder handschriftlich oder von einem Parser-Generator generiert) ist immer vorzuziehen. Nichtsdestotrotz zeigt der obige Code, wie Java Nashorn einfach integriert werden kann.
Vor einigen Monaten habe ich Esprima verwendet , um solche Eingaben zu analysieren. Eigentlich parst Esprima jede JavaScript-Eingabe (wandelt sie in einen Baum um), also sollte es für solche mathematischen Ausdrücke funktionieren.
Nachdem Sie Esprima hinzugefügt haben, können Sie Folgendes tun:
esprima.parse(input);
... wo input
ist ein String, der die Eingabe enthält, die analysiert werden soll (wenn sie ungültig ist, wird ein Fehler ausgegeben).
Beispiel
esprima.parse("1+2*3")
gibt das folgende Objekt zurück:
{
"type": "Program",
"body": [
{
"type": "ExpressionStatement",
"expression": {
"type": "BinaryExpression",
"operator": "+",
"left": {
"type": "Literal",
"value": 1,
"raw": "1"
},
"right": {
"type": "BinaryExpression",
"operator": "*",
"left": {
"type": "Literal",
"value": 2,
"raw": "2"
},
"right": {
"type": "Literal",
"value": 3,
"raw": "3"
}
}
}
}
]
}
Ich habe den Esprima-Code modifiziert und ihn in einem experimentellen Projekt verwendet, um benutzerdefinierte Operatoren in JavaScript zu definieren. Die Anwendung ist Open Source auf GitHub: http://ionicabizau.net/JavaScript-custom-operators/
Es scheint, dass JEP ein mathematischer Ausdrucksparser ist.
JEP ist eine Java-API zum Analysieren und Auswerten mathematischer Ausdrücke. Mit dieser Bibliothek können Sie Ihren Benutzern erlauben, eine beliebige Formel als Zeichenfolge einzugeben und sofort auszuwerten. JEP unterstützt benutzerdefinierte Variablen, Konstanten und Funktionen. Eine Reihe allgemeiner mathematischer Funktionen und Konstanten sind enthalten.
Merkmale
- Benutzerfreundliches Paket zum Analysieren mathematischer Ausdrücke
- Kleine Größe (nur 56kb als JAR-Archiv)
- Unterstützt boolesche Ausdrücke (!, &&, ||, <, >, !=, ==, >= und <=)
- Schnelle Auswertung (der Ausdruck kann schnell für verschiedene Variablenwerte ausgewertet werden)
- Enthält allgemeine mathematische Funktionen
- Erweiterbar durch benutzerdefinierte Funktionen
- Vordefinierte Konstanten wie 'pi' und 'e'
- Unterstützung für Zeichenfolgen, komplexe Zahlen und Vektoren
- Unterstützung für implizite Multiplikation (ermöglicht die Verwendung von Ausdrücken wie „3x“ anstelle von „3*x“)
- Ermöglicht die Wahl zwischen deklarierten und nicht deklarierten Variablen
- Kompatibel mit Java 1.1 (getestet mit Sun Java JDK 1.1.8 und der Microsoft Java VM)
- Unterstützt Unicode-Zeichen (einschließlich griechischer Symbole)
- Enthält JavaCC-Grammatik, aus der die Hauptklassen generiert werden
Es ist Open Source auf SourceForge .
Außerdem gibt es eine SO-Frage zu diesem Thema: https://stackoverflow.com/q/4589951/1420197
Das Erstellen von Formelparsern/Baumerstellern ist eine ziemlich einfache Übung. Sie können nach einer Bibliothek suchen, aber am Ende werden Sie sie immer modifizieren, um genau das zu produzieren, was Sie wollen. Stattdessen ist es wahrscheinlich einfacher, einfach zu codieren, was Sie wollen.
Wenn Sie etwas erheblich Komplexeres als einen Ausdruck parsen möchten, können Sie diese Art von Parser dazu drängen, aber in diesem Fall ist es im Allgemeinen einfacher, zum Parser-Generator zu wechseln.
Symja wandelt einen mathematischen Ausdruck in die folgende Symja AST um .
Ich habe javassist verwendet, um Java-Ausdrücke in Bytecode zu konvertieren (was Sie letztendlich suchen, wenn Sie den Ausdruck auswerten möchten). Es kann sogar bestehende Funktionen neu definieren.
ComFreek