Java 中有 eval() 函数吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2605032/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 09:46:27  来源:igfitidea点击:

Is there an eval() function in Java?

javaeval

提问by karthi_ms

I have a string like the following:

我有一个像下面这样的字符串:

String str = "4*5";

Now I have to get the result of 20by using the string.

现在我必须20通过使用字符串来获得结果。

I know in some other languages the eval()function will do this. How can I do this in Java?

我知道在其他一些语言中,该eval()函数会执行此操作。我怎样才能在 Java 中做到这一点?

采纳答案by Jeff Storey

You can use the ScriptEngineclass and evaluate it as a Javascript string.

您可以使用ScriptEngine该类并将其作为 Javascript 字符串进行评估。

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

There may be a better way, but this one works.

可能有更好的方法,但这个方法有效。

回答by DVK

No, you can not have a generic "eval" in Java (or any compiled language). Unless you're willing to write a Java compiler AND a JVM to be executed inside of your Java program.

,您不能在 Java(或任何编译语言)中使用通用的“eval”。除非你愿意编写一个 Java 编译器和一个 JVM 来在你的 Java 程序中执行。

Yes, you can have some library to evaluate numeric algebraic expressions like the one above - see this thread for discussion.

是的,您可以使用一些库来评估上述数字代数表达式 -请参阅此线程进行讨论

回答by Stephen C

There is no standard Java class or method that will do what you want. Your options include:

没有标准的 Java 类或方法可以满足您的需求。您的选择包括:

  • Select and use some third-party expression evaluation library. For example JELor any of the half dozen libraries listed here.

  • Wrap the expression in the Java source code for a class with an evalmethod, send that to the Java compiler, and then load the resulting compiled class.

  • Use some scripting language that can be called from Java as an expression evaluator. Possibilities include Javascript, BeanShell, and so on.

  • Write your own expression evaluator from scratch.

  • 选择并使用一些第三方表达式求值库。例如JEL此处列出的六个库中的任何一个。

  • 用一个eval方法将类的 Java 源代码中的表达式包装起来,将其发送到 Java 编译器,然后加载生成的编译类。

  • 使用一些可以从 Java 调用的脚本语言作为表达式评估器。可能性包括 Javascript、BeanShell 等。

  • 从头开始编写您自己的表达式计算器。

The first approach is probably simplest. The second and third approaches are a potential security risk if you get the expression to be evaluated from an untrusted user. (Think code injection.)

第一种方法可能是最简单的。如果您从不受信任的用户那里获得要评估的表达式,则第二种和第三种方法存在潜在的安全风险。(想想代码注入。)

回答by polygenelubricants

There is nothing that will do this in JavaSE; you'd have to find third-party libraries or write your own.

在 JavaSE 中没有任何东西可以做到这一点;您必须找到第三方库或编写自己的库。

回答by Adisesha

As previous answers, there is no standard API in Java for this.

正如之前的答案,Java 中没有为此提供标准 API。

You can add groovy jar files to your path and groovy.util.Eval.me("4*5") gets your job done.

您可以将 groovy jar 文件添加到您的路径中,groovy.util.Eval.me("4*5") 即可完成您的工作。

回答by Srneczek

Writing your own library is not that hard as u might thing. Here is link for Shunting-yard algorithmwith step by step algorithm explenation. Although, you will have to parse the input for tokens first.

编写自己的库并不像你想象的那么难。这里是链接调度场算法与分步算法explenation。虽然,您必须首先解析令牌的输入。

There are 2 other questions wich can give you some information too: Turn a String into a Math Expression?What's a good library for parsing mathematical expressions in java?

还有另外两个问题也可以为您提供一些信息: 将字符串转换为数学表达式?在java中解析数学表达式的好库是什么?

回答by Raedwald

There are very few real use cases in which being able to evaluate a Stringas a fragment of Java code is necessary or desirable. That is, asking how to do this is really an XY problem: you actually have a different problem, which can be solved a different way.

很少有真正的用例String需要或希望能够将 a 评估为 Java 代码的片段。也就是说,询问如何做到这一点实际上是一个XY 问题:您实际上有一个不同的问题,可以用不同的方式解决。

First ask yourself, where did this Stringthat you wish to evaluate come from? Did another part of your program generate it, or was it input provided by the user?

首先问问自己,String您要评估的这个是从哪里来的?你的程序的另一部分是生成它还是用户提供的输入?

  • Another part of my program generated it: so, you want one part of your program to decide the kind of operation to perform, but not perform the operation, and a second part that performs the chosen operation. Instead of generating and then evaluating a String, use the Strategy, Commandor Builderdesign pattern, as appropriate for your particular case.

  • It is user input: the user could input anything, including commands that, when executed, could cause your program to misbehave, crash, expose information that should be secret, damage persistent information (such as the content of a database), and other such nastiness. The only way to prevent that would be to parse the Stringyourself, check it was not malicious, and then evaluate it. But parsing it yourself is much of the work that the requested evalfunction would do, so you have saved yourself nothing. Worse still, checking that arbitrary Javawas not malicious is impossible, because checking that is the halting problem.

  • It is user input, but the syntax and semantics of permitted text to evaluate is greatly restricted: No general purpose facility can easily implement a general purpose parser and evaluator for whatever restricted syntax and semantics you have chosen. What you need to do is implement a parser and evaluator for your chosen syntax and semantics. If the task is simple, you could write a simple recursive-descentor finite-state-machine parser by hand. If the task is difficult, you could use a compiler-compiler(such as ANTLR) to do some of the work for you.

  • I just want to implement a desktop calculator!: A homework assignment, eh? If you could implement the evaluation of the input expression using a provided evalfunction, it would not be much of a homework assignment, would it? Your program would be three lines long. Your instructor probably expects you to write the code for a simple arithmetic parser/evaluator. There is well known algorithm, shunting-yard, which you might find useful.

  • 我的程序的另一部分生成了它:因此,您希望程序的一部分决定要执行的操作类型,但不执行操作,第二部分执行所选操作。不是生成然后评估 a String,而是根据您的特定情况使用StrategyCommandBuilder设计模式。

  • 它是用户输入:用户可以输入任何内容,包括在执行时可能导致您的程序行为异常、崩溃、暴露本应保密的信息、损坏持久信息(例如数据库的内容)以及其他类似的命令肮脏。防止这种情况的唯一方法是String自己解析,检查它是否是恶意的,然后对其进行评估。但是自己解析它是请求eval函数会做的大部分工作,所以你没有为自己节省任何东西。更糟糕的是,检查任意Java不是恶意的是不可能的,因为检查那是停机问题

  • 它是用户输入,但允许评估的文本的语法和语义受到极大限制:对于您选择的任何受限制的语法和语义,没有通用工具可以轻松实现通用解析器和评估器。您需要做的是为您选择的语法和语义实现解析器和评估器。如果任务很简单,您可以手动编写一个简单的递归下降或有限状态机解析器。如果任务很困难,您可以使用编译器-编译器(例如 ANTLR)来为您完成一些工作。

  • 我只想实现一个桌面计算器!: 家庭作业,嗯?如果您可以使用提供的eval函数来实现对输入表达式的评估,那么它就不是家庭作业,是吗?你的程序会有三行长。您的教师可能希望您为简单的算术解析器/评估器编写代码。有一个众所周知的算法shunting-yard,您可能会发现它很有用。

回答by chAlexey

I could advise you to use Exp4j. It is easy to understand as you can see from the following example code:

我可以建议您使用Exp4j。从以下示例代码中可以看出,它很容易理解:

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();

回答by VinceLomba

A fun way to solve your problem could be coding an eval() function on your own! I've done it for you!

一种解决问题的有趣方法可能是自己编写 eval() 函数!我已经为你做了!

You can use FunctionSolver library simply by typing FunctionSolver.solveByX(function,value)inside your code. The functionattribute is a String which represents the function you want to solve, the valueattribute is the value of the independent variable of your function (which MUST be x).

您只需在代码中键入FunctionSolver.solveByX( function, value)即可使用 FunctionSolver 库。该功能属性是代表你要解决功能的字符串,该属性是你的函数的自变量(必须是X)的值。

If you want to solve a function which contains more than one independent variable, you can use FunctionSolver.solve(function,values)where the valuesattribute is an HashMap(String,Double)which contains all your independent attributes (as Strings) and their respective values (as Doubles).

如果你想解决一个包含多个自变量的函数,你可以使用FunctionSolver.solve( function, values)其中values属性是一个HashMap(String,Double),它包含你所有的独立属性(作为字符串)和它们的各自的值(作为双打)。

Another piece of information: I've coded a simple version of FunctionSolver, so its supports only Math methodswhich return a double value and which accepts one or two double values as fields (just use FunctionSolver.usableMathMethods()if you're curious) (These methods are: bs, sin, cos, tan, atan2, sqrt, log, log10, pow, exp, min, max, copySign, signum, IEEEremainder, acos, asin, atan, cbrt, ceil, cosh, expm1, floor, hypot, log1p, nextAfter, nextDown, nextUp, random, rint, sinh, tanh, toDegrees, toRadians, ulp). Also, that library supports the following operators: * / + - ^ (even if java normally does not support the ^ operator).

另一条信息:我编写了一个简单版本的FunctionSolver,因此它仅支持返回 double 值并接受一个或两个 double 值作为字段的Math 方法如果您好奇,只需使用FunctionSolver.usableMathMethods()) (这些方法是:bs、sin、cos、tan、atan2、sqrt、log、log10、pow、exp、min、max、copySign、signum、IEEEremainder、acos、asin、atan、cbrt、ceil、cosh、expm1、floor , hypot, log1p, nextAfter, nextDown, nextUp, random, rint, sinh, tanh, toDegrees, toRadians, ulp)。此外,该库支持以下运算符: * / + - ^ (即使 java 通常不支持 ^ 运算符)。

One last thing: while creating this library I had to use reflectionsto call Math methods. I think it's really cool, just have a look at thisif you are interested in!

最后一件事:在创建这个库时,我不得不使用反射来调用Math 方法。我觉得它真的很酷,有兴趣的可以看看这个

That's all, here it is the code (and the 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();
}
 }

回答by abubakkar

As there are many answers, I'm adding my implementation on top of eval()method with some additional features like support for factorial, evaluating complex expressions etc.

由于有很多答案,我将我的实现添加到eval()方法之上,并带有一些附加功能,例如支持阶乘、计算复杂表达式等。

package evaluation;

import java.math.BigInteger;
import java.util.EmptyStackException;
import java.util.Scanner;
import java.util.Stack;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class EvalPlus {
    private static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) {
        System.out.println("This Evaluation is based on BODMAS rule\n");
        evaluate();
    }

    private static void evaluate() {
        StringBuilder finalStr = new StringBuilder();
        System.out.println("Enter an expression to evaluate:");
        String expr = scanner.nextLine(); 
        if(isProperExpression(expr)) {
            expr = replaceBefore(expr);
            char[] temp = expr.toCharArray();
            String operators = "(+-*/%)";
            for(int i = 0; i < temp.length; i++) {
                if((i == 0 && temp[i] != '*') || (i == temp.length-1 && temp[i] != '*' && temp[i] != '!')) {
                    finalStr.append(temp[i]);
                } else if((i > 0 && i < temp.length -1) || (i==temp.length-1 && temp[i] == '!')) {
                    if(temp[i] == '!') {
                        StringBuilder str = new StringBuilder();
                        for(int k = i-1; k >= 0; k--) {
                            if(Character.isDigit(temp[k])) {
                                str.insert(0, temp[k] );
                            } else {
                                break;
                            }
                        }
                        Long prev = Long.valueOf(str.toString());
                        BigInteger val = new BigInteger("1");
                        for(Long j = prev; j > 1; j--) {
                            val = val.multiply(BigInteger.valueOf(j));
                        }
                        finalStr.setLength(finalStr.length() - str.length());
                        finalStr.append("(" + val + ")");
                        if(temp.length > i+1) {
                            char next = temp[i+1];
                            if(operators.indexOf(next) == -1) { 
                                finalStr.append("*");
                            }
                        }
                    } else {
                        finalStr.append(temp[i]);
                    }
                }
            }
            expr = finalStr.toString();
            if(expr != null && !expr.isEmpty()) {
                ScriptEngineManager mgr = new ScriptEngineManager();
                ScriptEngine engine = mgr.getEngineByName("JavaScript");
                try {
                    System.out.println("Result: " + engine.eval(expr));
                    evaluate();
                } catch (ScriptException e) {
                    System.out.println(e.getMessage());
                }
            } else {
                System.out.println("Please give an expression");
                evaluate();
            }
        } else {
            System.out.println("Not a valid expression");
            evaluate();
        }
    }

    private static String replaceBefore(String expr) {
        expr = expr.replace("(", "*(");
        expr = expr.replace("+*", "+").replace("-*", "-").replace("**", "*").replace("/*", "/").replace("%*", "%");
        return expr;
    }

    private static boolean isProperExpression(String expr) {
        expr = expr.replaceAll("[^()]", "");
        char[] arr = expr.toCharArray();
        Stack<Character> stack = new Stack<Character>();
        int i =0;
        while(i < arr.length) {
            try {
                if(arr[i] == '(') {
                    stack.push(arr[i]);
                } else {
                    stack.pop();
                }
            } catch (EmptyStackException e) {
                stack.push(arr[i]);
            }
            i++;
        }
        return stack.isEmpty();
    }
}

Please find the updated gist anytime here. Also comment if any issues are there. Thanks.

请随时在此处找到更新的要点。如果有任何问题,也可以发表评论。谢谢。