Estoy buscando una biblioteca de Java que pueda analizar fórmulas matemáticas en un AST (árbol de sintaxis abstracta).
ACTUALIZACIÓN:
estoy abierto a alternativas en lenguajes que no sean Java, siempre que pueda llamar a estas herramientas/bibliotecas desde Java.
Por ejemplo, JavaScript se puede incrustar usando el motor Rhino .
Requerimientos esenciales:
La capacidad de analizar fórmulas en notación infija .
La capacidad de preservar variables desconocidas: no estoy buscando una calculadora.
Una lista personalizable de operadores y funciones.
También sería excelente si se pudieran eliminar las funciones ya integradas (por ejemplo, sin(x)
).
Requisitos no esenciales:
“Math.js es una extensa biblioteca matemática para JavaScript y Node.js”.
— Léame del proyecto
Proporciona una función parse() .
Ejemplo utilizando el entorno NodeJS:
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}));
Producción:
{ op: '^',
fn: 'pow',
params:
[ { name: 'xy' },
{ op: '/',
fn: 'divide',
params:
[ { valueType: 'number', value: '1' },
{ valueType: 'number', value: '2' } ] } ] }
Utilizo Java Nashorn VM (solo disponible en Java >= 8) para ejecutar JavaScript.
Arquitectura del programa:
User ---------------> Java
inputs formla |----> Nashorn ----> math.js
|<---------------------|
User <-----------------|
Usar el motor Nashorn es bastante simple (se omite el manejo de excepciones)
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(readerInstancePointingToMathJsLibrary);
engine.eval(readerInstancePointingToBridgeJavaScript);
El código JavaScript del puente depende en gran medida de la implementación de los nodos AST. Aprovechamos la capacidad de Nashorn para crear y transferir objetos Java en JavaScript a Java. Ejemplo:
var math = mathjs();
function convert(formula) {
var ast = math.parse(formula);
var javaAst = /* build your AST with Java objects */
return javaAst;
}
Ahora podemos acceder a esa función desde Java e incluso pasar argumentos arbitrarios:
Invocable inv = (Invocable) engine;
// Expression is my AST node type in Java
expr = (Expression) inv.invokeFunction("convert", formulaFromUser);
Nota: necesitaba una forma rápida de analizar expresiones matemáticas. Siempre es preferible un analizador (ya sea escrito a mano o generado por un generador de analizador). No obstante, el código anterior muestra cómo se puede integrar fácilmente Java Nashorn.
Hace unos meses, utilicé Esprima para analizar dichas entradas. En realidad, Esprima analiza cualquier entrada de JavaScript (convirtiéndola en un árbol), por lo que debería funcionar para tales expresiones matemáticas.
Después de incluir Esprima, puede hacer:
esprima.parse(input);
... donde input
hay una cadena que contiene la entrada que debe analizarse (si no es válida, se generará un error).
Ejemplo
esprima.parse("1+2*3")
devuelve el siguiente objeto:
{
"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"
}
}
}
}
]
}
Modifiqué el código de Esprima y lo usé en un proyecto experimental para definir operadores personalizados en JavaScript. La aplicación es de código abierto en GitHub: http://ionicabizau.net/JavaScript-custom-operators/
Parece que JEP es un analizador de expresiones matemáticas.
JEP es una API de Java para analizar y evaluar expresiones matemáticas. Con esta biblioteca, puede permitir que sus usuarios ingresen una fórmula arbitraria como una cadena y la evalúen instantáneamente. JEP admite variables, constantes y funciones definidas por el usuario. Se incluyen varias funciones y constantes matemáticas comunes.
Características
- Paquete fácil de usar para analizar expresiones matemáticas
- Tamaño pequeño (solo 56kb como archivo jar)
- Admite expresiones booleanas (!, &&, ||, <, >, !=, ==, >= y <=)
- Evaluación rápida (la expresión se puede evaluar rápidamente para diferentes valores de variables)
- Incluye funciones matemáticas comunes
- Ampliable a través de funciones definidas por el usuario
- Constantes predefinidas como 'pi' y 'e'
- Compatibilidad con cadenas, números complejos y vectores
- Compatibilidad con la multiplicación implícita (permite el uso de expresiones como "3x" en lugar de "3*x")
- Permite elegir entre variables declaradas y no declaradas
- Compatible con Java 1.1 (probado con Sun Java JDK 1.1.8 y Microsoft Java VM)
- Admite caracteres Unicode (incluidos los símbolos griegos)
- Incluye gramática JavaCC a partir de la cual se generan las clases principales
Es de código abierto en SourceForge .
Además, hay una pregunta SO sobre este tema: https://stackoverflow.com/q/4589951/1420197
Construir analizadores de fórmulas/constructores de árboles es un ejercicio bastante simple. Puede buscar una biblioteca, pero siempre terminará modificándola para producir exactamente lo que desea. En cambio, es probable que sea más fácil simplemente codificar lo que desea.
Si desea analizar algo considerablemente más complejo que una expresión, puede presionar este tipo de analizador para que lo haga, pero generalmente es más fácil cambiar al generador de analizador en ese caso.
He usado javassist para convertir expresiones Java en código de bytes (que puede ser lo que finalmente esté buscando si desea evaluar la expresión). Incluso puede redefinir funciones existentes.
ComFreek