funcion java eval

funcion - eval javascript



¿Hay una función eval() en Java? (9)

¡Una forma divertida de resolver su problema podría ser codificar una función eval () usted mismo! ¡Lo he hecho por ti!

Puede usar la biblioteca FunctionSolver simplemente escribiendo FunctionSolver.solveByX ( función , valor ) dentro de su código. El atributo de función es una Cadena que representa la función que desea resolver, el atributo de valor es el valor de la variable independiente de su función (que DEBE ser x).

Si desea resolver una función que contiene más de una variable independiente, puede usar FunctionSolver.solve ( función , valores ) donde el atributo de valores es un HashMap(String,Double) que contiene todos sus atributos independientes (como Strings) y sus valores respectivos (como Dobles).

Otra información: he codificado una versión simple de FunctionSolver , por lo que solo admite los métodos matemáticos que devuelven un valor doble y aceptan uno o dos valores dobles como campos (solo use FunctionSolver.usableMathMethods () si tiene curiosidad) (Estos métodos son: bs, sin, cos, tan, atan2, sqrt, log, log10, pow, exp, min, max, copySign, signum, IEEEremainder, acos, asin, atan, cbrt, ceil, cosh, expm1, piso , hypot, log1p, nextAfter, nextDown, nextUp, random, rint, sinh, tanh, toDegrees, toRadians, ulp) . Además, esa biblioteca admite los siguientes operadores: * / + - ^ (incluso si java normalmente no admite el operador ^).

Una última cosa: al crear esta biblioteca, tuve que usar reflections para llamar a los métodos matemáticos . Creo que es genial, ¡ reflections si está interesado!

Eso es todo, aquí está el código (y la library ):

package core; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; public abstract class FunctionSolver { public static double solveNumericExpression (String expression) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { return solve(expression, new HashMap<>()); } public static double solveByX (String function, double value) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { HashMap<String, Double> values = new HashMap<>(); values.put("x", value); return solveComplexFunction(function, function, values); } public static double solve (String function, HashMap<String,Double> values) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { return solveComplexFunction(function, function, values); } private static double solveComplexFunction (String function, String motherFunction, HashMap<String, Double> values) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { int position = 0; while(position < function.length()) { if (alphabetic.contains(""+function.charAt(position))) { if (position == 0 || !alphabetic.contains(""+function.charAt(position-1))) { int endIndex = -1; for (int j = position ; j < function.length()-1 ; j++) { if (alphabetic.contains(""+function.charAt(j)) && !alphabetic.contains(""+function.charAt(j+1))) { endIndex = j; break; } } if (endIndex == -1 & alphabetic.contains(""+function.charAt(function.length()-1))) { endIndex = function.length()-1; } if (endIndex != -1) { String alphabeticElement = function.substring(position, endIndex+1); if (Arrays.asList(usableMathMethods()).contains(alphabeticElement)) { //Start analyzing a Math function int closeParenthesisIndex = -1; int openedParenthesisquantity = 0; int commaIndex = -1; for (int j = endIndex+1 ; j < function.length() ; j++) { if (function.substring(j,j+1).equals("(")) { openedParenthesisquantity++; }else if (function.substring(j,j+1).equals(")")) { openedParenthesisquantity--; if (openedParenthesisquantity == 0) { closeParenthesisIndex = j; break; } }else if (function.substring(j,j+1).equals(",") & openedParenthesisquantity == 0) { if (commaIndex == -1) { commaIndex = j; }else{ throw new IllegalArgumentException("The argument of math function (which is "+alphabeticElement+") has too many commas"); } } } if (closeParenthesisIndex == -1) { throw new IllegalArgumentException("The argument of a Math function (which is "+alphabeticElement+") hasn''t got the closing bracket )"); } String functionArgument = function.substring(endIndex+2,closeParenthesisIndex); if (commaIndex != -1) { double firstParameter = solveComplexFunction(functionArgument.substring(0,commaIndex),motherFunction,values); double secondParameter = solveComplexFunction(functionArgument.substring(commaIndex+1),motherFunction,values); Method mathMethod = Math.class.getDeclaredMethod(alphabeticElement, new Class<?>[] {double.class, double.class}); mathMethod.setAccessible(true); String newKey = getNewKey(values); values.put(newKey, (Double) mathMethod.invoke(null, firstParameter, secondParameter)); function = function.substring(0, position)+newKey +((closeParenthesisIndex == function.length()-1)?(""):(function.substring(closeParenthesisIndex+1))); }else { double firstParameter = solveComplexFunction(functionArgument, motherFunction, values); Method mathMethod = Math.class.getDeclaredMethod(alphabeticElement, new Class<?>[] {double.class}); mathMethod.setAccessible(true); String newKey = getNewKey(values); values.put(newKey, (Double) mathMethod.invoke(null, firstParameter)); function = function.substring(0, position)+newKey +((closeParenthesisIndex == function.length()-1)?(""):(function.substring(closeParenthesisIndex+1))); } }else if (!values.containsKey(alphabeticElement)) { throw new IllegalArgumentException("Found a group of letters ("+alphabeticElement+") which is neither a variable nor a Math function: "); } } } } position++; } return solveBracketsFunction(function,motherFunction,values); } private static double solveBracketsFunction (String function,String motherFunction,HashMap<String, Double> values) throws IllegalArgumentException{ function = function.replace(" ", ""); String openingBrackets = "([{"; String closingBrackets = ")]}"; int parenthesisIndex = 0; do { int position = 0; int openParenthesisBlockIndex = -1; String currentOpeningBracket = openingBrackets.charAt(parenthesisIndex)+""; String currentClosingBracket = closingBrackets.charAt(parenthesisIndex)+""; if (contOccouranceIn(currentOpeningBracket,function) != contOccouranceIn(currentClosingBracket,function)) { throw new IllegalArgumentException("Error: brackets are misused in the function "+function); } while (position < function.length()) { if (function.substring(position,position+1).equals(currentOpeningBracket)) { if (position != 0 && !operators.contains(function.substring(position-1,position))) { throw new IllegalArgumentException("Error in function: there must be an operator following a "+currentClosingBracket+" breacket"); } openParenthesisBlockIndex = position; }else if (function.substring(position,position+1).equals(currentClosingBracket)) { if (position != function.length()-1 && !operators.contains(function.substring(position+1,position+2))) { throw new IllegalArgumentException("Error in function: there must be an operator before a "+currentClosingBracket+" breacket"); } String newKey = getNewKey(values); values.put(newKey, solveBracketsFunction(function.substring(openParenthesisBlockIndex+1,position),motherFunction, values)); function = function.substring(0,openParenthesisBlockIndex)+newKey +((position == function.length()-1)?(""):(function.substring(position+1))); position = -1; } position++; } parenthesisIndex++; }while (parenthesisIndex < openingBrackets.length()); return solveBasicFunction(function,motherFunction, values); } private static double solveBasicFunction (String function, String motherFunction, HashMap<String, Double> values) throws IllegalArgumentException{ if (!firstContainsOnlySecond(function, alphanumeric+operators)) { throw new IllegalArgumentException("The function "+function+" is not a basic function"); } if (function.contains("**") | function.contains("//") | function.contains("--") | function.contains("+*") | function.contains("+/") | function.contains("-*") | function.contains("-/")) { /* * ( -+ , +- , *- , *+ , /- , /+ )> Those values are admitted */ throw new IllegalArgumentException("Operators are misused in the function"); } function = function.replace(" ", ""); int position; int operatorIndex = 0; String currentOperator; do { currentOperator = operators.substring(operatorIndex,operatorIndex+1); if (currentOperator.equals("*")) { currentOperator+="/"; operatorIndex++; }else if (currentOperator.equals("+")) { currentOperator+="-"; operatorIndex++; } operatorIndex++; position = 0; while (position < function.length()) { if ((position == 0 && !(""+function.charAt(position)).equals("-") && !(""+function.charAt(position)).equals("+") && operators.contains(""+function.charAt(position))) || (position == function.length()-1 && operators.contains(""+function.charAt(position)))){ throw new IllegalArgumentException("Operators are misused in the function"); } if (currentOperator.contains(function.substring(position, position+1)) & position != 0) { int firstTermBeginIndex = position; while (firstTermBeginIndex > 0) { if ((alphanumeric.contains(""+function.charAt(firstTermBeginIndex))) & (operators.contains(""+function.charAt(firstTermBeginIndex-1)))){ break; } firstTermBeginIndex--; } if (firstTermBeginIndex != 0 && (function.charAt(firstTermBeginIndex-1) == ''-'' | function.charAt(firstTermBeginIndex-1) == ''+'')) { if (firstTermBeginIndex == 1) { firstTermBeginIndex--; }else if (operators.contains(""+(function.charAt(firstTermBeginIndex-2)))){ firstTermBeginIndex--; } } String firstTerm = function.substring(firstTermBeginIndex,position); int secondTermLastIndex = position; while (secondTermLastIndex < function.length()-1) { if ((alphanumeric.contains(""+function.charAt(secondTermLastIndex))) & (operators.contains(""+function.charAt(secondTermLastIndex+1)))) { break; } secondTermLastIndex++; } String secondTerm = function.substring(position+1,secondTermLastIndex+1); double result; switch (function.substring(position,position+1)) { case "*": result = solveSingleValue(firstTerm,values)*solveSingleValue(secondTerm,values); break; case "/": result = solveSingleValue(firstTerm,values)/solveSingleValue(secondTerm,values); break; case "+": result = solveSingleValue(firstTerm,values)+solveSingleValue(secondTerm,values); break; case "-": result = solveSingleValue(firstTerm,values)-solveSingleValue(secondTerm,values); break; case "^": result = Math.pow(solveSingleValue(firstTerm,values),solveSingleValue(secondTerm,values)); break; default: throw new IllegalArgumentException("Unknown operator: "+currentOperator); } String newAttribute = getNewKey(values); values.put(newAttribute, result); function = function.substring(0,firstTermBeginIndex)+newAttribute+function.substring(secondTermLastIndex+1,function.length()); deleteValueIfPossible(firstTerm, values, motherFunction); deleteValueIfPossible(secondTerm, values, motherFunction); position = -1; } position++; } }while (operatorIndex < operators.length()); return solveSingleValue(function, values); } private static double solveSingleValue (String singleValue, HashMap<String, Double> values) throws IllegalArgumentException{ if (isDouble(singleValue)) { return Double.parseDouble(singleValue); }else if (firstContainsOnlySecond(singleValue, alphabetic)){ return getValueFromVariable(singleValue, values); }else if (firstContainsOnlySecond(singleValue, alphanumeric+"-+")) { String[] composition = splitByLettersAndNumbers(singleValue); if (composition.length != 2) { throw new IllegalArgumentException("Wrong expression: "+singleValue); }else { if (composition[0].equals("-")) { composition[0] = "-1"; }else if (composition[1].equals("-")) { composition[1] = "-1"; }else if (composition[0].equals("+")) { composition[0] = "+1"; }else if (composition[1].equals("+")) { composition[1] = "+1"; } if (isDouble(composition[0])) { return Double.parseDouble(composition[0])*getValueFromVariable(composition[1], values); }else if (isDouble(composition[1])){ return Double.parseDouble(composition[1])*getValueFromVariable(composition[0], values); }else { throw new IllegalArgumentException("Wrong expression: "+singleValue); } } }else { throw new IllegalArgumentException("Wrong expression: "+singleValue); } } private static double getValueFromVariable (String variable, HashMap<String, Double> values) throws IllegalArgumentException{ Double val = values.get(variable); if (val == null) { throw new IllegalArgumentException("Unknown variable: "+variable); }else { return val; } } /* * FunctionSolver help tools: * */ private static final String alphabetic = "abcdefghilmnopqrstuvzwykxy"; private static final String numeric = "0123456789."; private static final String alphanumeric = alphabetic+numeric; private static final String operators = "^*/+-"; //--> Operators order in important! private static boolean firstContainsOnlySecond(String firstString, String secondString) { for (int j = 0 ; j < firstString.length() ; j++) { if (!secondString.contains(firstString.substring(j, j+1))) { return false; } } return true; } private static String getNewKey (HashMap<String, Double> hashMap) { String alpha = "abcdefghilmnopqrstuvzyjkx"; for (int j = 0 ; j < alpha.length() ; j++) { String k = alpha.substring(j,j+1); if (!hashMap.containsKey(k) & !Arrays.asList(usableMathMethods()).contains(k)) { return k; } } for (int j = 0 ; j < alpha.length() ; j++) { for (int i = 0 ; i < alpha.length() ; i++) { String k = alpha.substring(j,j+1)+alpha.substring(i,i+1); if (!hashMap.containsKey(k) & !Arrays.asList(usableMathMethods()).contains(k)) { return k; } } } throw new NullPointerException(); } public static String[] usableMathMethods () { /* * Only methods that: * return a double type * present one or two parameters (which are double type) */ Method[] mathMethods = Math.class.getDeclaredMethods(); ArrayList<String> usableMethodsNames = new ArrayList<>(); for (Method method : mathMethods) { boolean usable = true; int argumentsCounter = 0; Class<?>[] methodParametersTypes = method.getParameterTypes(); for (Class<?> parameter : methodParametersTypes) { if (!parameter.getSimpleName().equalsIgnoreCase("double")) { usable = false; break; }else { argumentsCounter++; } } if (!method.getReturnType().getSimpleName().toLowerCase().equals("double")) { usable = false; } if (usable & argumentsCounter<=2) { usableMethodsNames.add(method.getName()); } } return usableMethodsNames.toArray(new String[usableMethodsNames.size()]); } private static boolean isDouble (String number) { try { Double.parseDouble(number); return true; }catch (Exception ex) { return false; } } private static String[] splitByLettersAndNumbers (String val) { if (!firstContainsOnlySecond(val, alphanumeric+"+-")) { throw new IllegalArgumentException("Wrong passed value: <<"+val+">>"); } ArrayList<String> response = new ArrayList<>(); String searchingFor; int lastIndex = 0; if (firstContainsOnlySecond(""+val.charAt(0), numeric+"+-")) { searchingFor = alphabetic; }else { searchingFor = numeric+"+-"; } for (int j = 0 ; j < val.length() ; j++) { if (searchingFor.contains(val.charAt(j)+"")) { response.add(val.substring(lastIndex, j)); lastIndex = j; if (searchingFor.equals(numeric+"+-")) { searchingFor = alphabetic; }else { searchingFor = numeric+"+-"; } } } response.add(val.substring(lastIndex,val.length())); return response.toArray(new String[response.size()]); } private static void deleteValueIfPossible (String val, HashMap<String, Double> values, String function) { if (values.get(val) != null & function != null) { if (!function.contains(val)) { values.remove(val); } } } private static int contOccouranceIn (String howManyOfThatString, String inThatString) { return inThatString.length() - inThatString.replace(howManyOfThatString, "").length(); } }

Tengo una cadena como la siguiente:

String str = "4*5";

Ahora tengo que obtener el resultado de 20 usando la cadena.

Sé que en otros idiomas la función eval() hará esto. ¿Cómo puedo hacer esto en Java?


Como respuestas anteriores, no hay una API estándar en Java para esto.

Puede agregar archivos groovy jar a su ruta y groovy.util.Eval.me ("4 * 5") hace su trabajo.



Hay muy pocos casos de uso real en los que sea necesario o deseable poder evaluar un String como un fragmento de código Java. Es decir, preguntar cómo hacer esto es realmente un problema XY : en realidad tiene un problema diferente, que puede resolverse de otra manera.

Primero pregúntate, ¿de dónde viene esta String que deseas evaluar? ¿Otra parte de tu programa lo generó, o fue una entrada proporcionada por el usuario?

  • Otra parte de mi programa lo generó : por lo tanto, quiere que una parte de su programa decida el tipo de operación a realizar, pero no la realice, y una segunda parte que realice la operación elegida. En lugar de generar y luego evaluar una String , use el patrón de diseño Strategy , Command o Builder , según corresponda para su caso particular.

  • Es la entrada del usuario: el usuario puede ingresar cualquier cosa , incluso comandos que, cuando se ejecutan, pueden hacer que su programa se comporte mal, bloquear, exponer información que debe ser secreta, dañar la información persistente (como el contenido de una base de datos) y otros suciedad. La única forma de prevenir eso sería analizar el String usted mismo, verificar que no sea malicioso y luego evaluarlo. Pero analizarlo usted mismo es una gran parte del trabajo que haría la función de eval solicitada, por lo que no se ha ahorrado nada. Peor aún, comprobar que Java arbitrario no era malicioso es imposible , porque comprobar que es el problema de detención .

  • Es la entrada del usuario, pero la sintaxis y la semántica del texto permitido para evaluar está muy restringida : ninguna función de propósito general puede implementar fácilmente un analizador y un evaluador de propósito general para la sintaxis restringida y la semántica que haya elegido. Lo que necesita hacer es implementar un analizador y un evaluador para su sintaxis y semántica elegidas. Si la tarea es simple, podría escribir a mano un analizador de recursive-descent o de estado finito simple. Si la tarea es difícil, puede usar un compiler-compiler (como ANTLR) para hacer parte del trabajo por usted.

  • ¡Solo quiero implementar una calculadora de escritorio! : Una tarea de tarea, ¿eh? Si pudieras implementar la evaluación de la expresión de entrada usando una función eval proporcionada, no sería una gran tarea, ¿verdad? Su programa sería de tres líneas de largo. Su instructor probablemente espera que escriba el código para un analizador / grabador aritmético simple. Existe un algoritmo bien conocido, shunting-yard , que puede serle útil.


No hay nada que haga esto en JavaSE; tendrías que buscar bibliotecas de terceros o escribir las tuyas propias.


No hay una clase o método Java estándar que haga lo que usted desea. Sus opciones incluyen:

  • Seleccione y use alguna biblioteca de evaluación de expresiones de terceros. Por ejemplo, JEL o cualquiera de las media docenas de bibliotecas enumeradas here .

  • Envuelva la expresión en el código fuente de Java para una clase con un método eval , envíe eso al compilador de Java, y luego cargue la clase compilada resultante.

  • Utilice un lenguaje de scripts que pueda invocarse desde Java como evaluador de expresiones. Las posibilidades incluyen Javascript, BeanShell, etc.

  • Escribe tu propio evaluador de expresiones desde cero.

El primer enfoque es probablemente el más simple. El segundo y tercer enfoque son un posible riesgo de seguridad si obtiene la expresión para ser evaluada por un usuario que no es de confianza. (Piensa en la inyección de código)


Podría aconsejarle que use Exp4j . Es fácil de entender, como puede ver en el siguiente código de ejemplo:

Expression e = new ExpressionBuilder("3 * sin(y) - 2 / (x - 2)") .variables("x", "y") .build() .setVariable("x", 2.3) .setVariable("y", 3.14); double result = e.evaluate();


Puede usar la clase ScriptEngine y evaluarla como una cadena de Javascript.

ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("js"); Object result = engine.eval("4*5");

Puede haber una mejor manera, pero esta funciona.


No , no puede tener un "eval" genérico en Java (o en cualquier lenguaje compilado). A menos que esté dispuesto a escribir un compilador Java Y una JVM para ser ejecutado dentro de su programa Java .

, puede tener alguna biblioteca para evaluar expresiones algebraicas numéricas como la de arriba - vea este hilo para discusión .