Как оценить математическое выражение в виде строки?

Я пытаюсь написать Java-процедуру для вычисления простых математических выражений из значений String, например:

  • "5+3"
  • "10-40"
  • "10*3"

Я хочу избежать множества операторов if-then-else. Как я могу это сделать?

Ответ 1

С JDK1.6 вы можете использовать встроенный механизм Javascript.

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;

public class Test {
  public static void main(String[] args) throws ScriptException {
    ScriptEngineManager mgr = new ScriptEngineManager();
    ScriptEngine engine = mgr.getEngineByName("JavaScript");
    String foo = "40+2";
    System.out.println(engine.eval(foo));
    } 
}

Ответ 2

Я написал этот метод eval для арифметических выражений, чтобы ответить на этот вопрос. Это добавление, вычитание, умножение, деление, возведение в степень (с использованием символа ^) и несколько основных функций, таких как sqrt. Он поддерживает группировку с помощью (... ) и получает оператор приоритет и associativity правильные правила.

public static double eval(final String str) {
    return new Object() {
        int pos = -1, ch;

        void nextChar() {
            ch = (++pos < str.length()) ? str.charAt(pos) : -1;
        }

        boolean eat(int charToEat) {
            while (ch == ' ') nextChar();
            if (ch == charToEat) {
                nextChar();
                return true;
            }
            return false;
        }

        double parse() {
            nextChar();
            double x = parseExpression();
            if (pos < str.length()) throw new RuntimeException("Unexpected: " + (char)ch);
            return x;
        }

        // Grammar:
        // expression = term | expression `+` term | expression `-` term
        // term = factor | term `*` factor | term `/` factor
        // factor = `+` factor | `-` factor | `(` expression `)`
        //        | number | functionName factor | factor `^` factor

        double parseExpression() {
            double x = parseTerm();
            for (;;) {
                if      (eat('+')) x += parseTerm(); // addition
                else if (eat('-')) x -= parseTerm(); // subtraction
                else return x;
            }
        }

        double parseTerm() {
            double x = parseFactor();
            for (;;) {
                if      (eat('*')) x *= parseFactor(); // multiplication
                else if (eat('/')) x /= parseFactor(); // division
                else return x;
            }
        }

        double parseFactor() {
            if (eat('+')) return parseFactor(); // unary plus
            if (eat('-')) return -parseFactor(); // unary minus

            double x;
            int startPos = this.pos;
            if (eat('(')) { // parentheses
                x = parseExpression();
                eat(')');
            } else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
                while ((ch >= '0' && ch <= '9') || ch == '.') nextChar();
                x = Double.parseDouble(str.substring(startPos, this.pos));
            } else if (ch >= 'a' && ch <= 'z') { // functions
                while (ch >= 'a' && ch <= 'z') nextChar();
                String func = str.substring(startPos, this.pos);
                x = parseFactor();
                if (func.equals("sqrt")) x = Math.sqrt(x);
                else if (func.equals("sin")) x = Math.sin(Math.toRadians(x));
                else if (func.equals("cos")) x = Math.cos(Math.toRadians(x));
                else if (func.equals("tan")) x = Math.tan(Math.toRadians(x));
                else throw new RuntimeException("Unknown function: " + func);
            } else {
                throw new RuntimeException("Unexpected: " + (char)ch);
            }

            if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation

            return x;
        }
    }.parse();
}

Пример:

System.out.println(eval("((4 - 2^3 + 1) * -sqrt(3*3+4*4)) / 2"));

Результат: 7.5 (что правильно)


Парсер - это рекурсивный синтаксический анализатор спуска, поэтому он использует отдельные методы анализа для каждого уровня приоритета оператора в своей грамматике. Я сохранил его короткий, поэтому его легко изменить, но вот некоторые идеи, которые вы можете расширить, с помощью:

  • Переменные:

    Бит анализатора, который читает имена функций, может быть легко изменен для обработки собственных переменных, путем поиска имен в таблице переменных, переданных методу eval, например Map<String,Double> variables.

  • Отдельная компиляция и оценка:

    Что делать, если, добавив поддержку переменных, вы хотели бы оценить одно и то же выражение миллионы раз с измененными переменными без разбора его каждый раз? Возможно. Сначала определите интерфейс, который будет использоваться для оценки прекомпилированного выражения:

    @FunctionalInterface
    interface Expression {
        double eval();
    }
    

    Теперь измените все методы, возвращающие double s, поэтому вместо этого они возвращают экземпляр этого интерфейса. Синтаксис Java 8 lambda отлично подходит для этого. Пример одного из измененных методов:

    Expression parseExpression() {
        Expression x = parseTerm();
        for (;;) {
            if (eat('+')) { // addition
                Expression a = x, b = parseTerm();
                x = (() -> a.eval() + b.eval());
            } else if (eat('-')) { // subtraction
                Expression a = x, b = parseTerm();
                x = (() -> a.eval() - b.eval());
            } else {
                return x;
            }
        }
    }
    

    Это создает рекурсивное дерево Expression объектов, представляющих скомпилированное выражение (абстрактное синтаксическое дерево). Затем вы можете скомпилировать его один раз и многократно оценивать его разными значениями:

    public static void main(String[] args) {
        Map<String,Double> variables = new HashMap<>();
        Expression exp = parse("x^2 - x + 2", variables);
        for (double x = -20; x <= +20; x++) {
            variables.put("x", x);
            System.out.println(x + " => " + exp.eval());
        }
    }
    
  • Различные типы данных:

    Вместо double вы можете изменить оценщика, чтобы использовать что-то более мощное, например BigDecimal, или класс, который реализует комплексные числа, или рациональные числа (дроби). Вы даже можете использовать Object, позволяя смешивать типы данных в выражениях, точно так же, как настоящий язык программирования.:)


Весь код в этом ответе опубликовал в общедоступном домене. Получайте удовольствие!

Ответ 3

Правильный способ решить это с помощью lexer и parser. Вы можете сами писать простые версии, или эти страницы также содержат ссылки на Java-лексеры и парсеры.

Создание рекурсивного парсера спуска - действительно хорошее упражнение.

Ответ 4

ЗДЕСЬ - еще одна библиотека с открытым исходным кодом на GitHub с именем EvalEx.

В отличие от механизма JavaScript эта библиотека ориентирована только на оценку математических выражений. Кроме того, библиотека расширяема и поддерживает использование логических операторов, а также круглых скобок.

Ответ 5

Вы также можете попробовать BeanShell интерпретатор:

Interpreter interpreter = new Interpreter();
interpreter.eval("result = (7+21*6)/(32-27)");
System.out.println(interpreter.get("result"));

Ответ 6

Вы можете легко оценивать выражения, если ваше приложение Java уже обращается к базе данных без использования каких-либо других JAR.

В некоторых базах данных вы должны использовать фиктивную таблицу (например, таблицу "dual" Oracle), а другие позволят вам оценивать выражения без "выбора" из любой таблицы.

Например, в Sql Server или Sqlite

select (((12.10 +12.0))/ 233.0) amount

и в Oracle

select (((12.10 +12.0))/ 233.0) amount from dual;

Преимущество использования БД состоит в том, что вы можете одновременно оценить множество выражений. Также большинство БД позволят вам использовать очень сложные выражения и также будут иметь ряд дополнительных функций, которые можно назвать необходимыми.

Однако производительность может пострадать, если несколько отдельных выражений нужно оценивать индивидуально, особенно когда БД находится на сетевом сервере.

Ниже перечислены проблемы производительности в некоторой степени, используя базу данных Sqlite в памяти.

Здесь полный рабочий пример в Java

Class. forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection("jdbc:sqlite::memory:");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery( "select (1+10)/20.0 amount");
rs.next();
System.out.println(rs.getBigDecimal(1));
stat.close();
conn.close();

Конечно, вы могли бы расширить вышеуказанный код для одновременного обработки нескольких вычислений.

ResultSet rs = stat.executeQuery( "select (1+10)/20.0 amount, (1+100)/20.0 amount2");

Ответ 7

Для моего университетского проекта я искал парсера/оценщика, поддерживающего как основные формулы, так и более сложные уравнения (особенно повторяющиеся операторы). Я нашел очень хорошую библиотеку с открытым исходным кодом для JAVA и.NET под названием mXparser. Я приведу несколько примеров, чтобы немного посидеть в синтаксисе, для получения дальнейших инструкций посетите веб-сайт проекта (особенно раздел "Учебник").

http://mathparser.org/

http://mathparser.org/mxparser-tutorial/

http://mathparser.org/api/

И несколько примеров

1 - Простая механика

Expression e = new Expression("( 2 + 3/4 + sin(pi) )/2");
double v = e.calculate()

2 - Пользовательские аргументы и константы

Argument x = new Argument("x = 10");
Constant a = new Constant("a = pi^2");
Expression e = new Expression("cos(a*x)", x, a);
double v = e.calculate()

3 - Пользовательские функции

Function f = new Function("f(x, y, z) = sin(x) + cos(y*z)");
Expression e = new Expression("f(3,2,5)", f);
double v = e.calculate()

4 - Итерация

Expression e = new Expression("sum( i, 1, 100, sin(i) )");
double v = e.calculate()

С наилучшими пожеланиями

Ответ 8

Эта статья указывает на 3 разных подхода, один из которых JEXL из Apache и позволяет создавать сценарии, содержащие ссылки на объекты Java.

Ответ 9

Другим способом является использование выражения Spring Expression Language или SpEL, который делает намного больше, наряду с оценкой математических выражений, поэтому может немного переборщить. Вам не обязательно использовать фреймворк Spring, чтобы использовать эту библиотеку выражений, поскольку она является автономной. Копирование примеров из документации Spel:

ExpressionParser parser = new SpelExpressionParser();
int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2 
double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); //24.0

Прочтите более сжатые примеры SpEL здесь и полные документы здесь

Ответ 10

Это еще одна интересная альтернатива https://github.com/Shy-Ta/expression-evaluator-demo

Использование очень простое и выполняет задание, например:

  ExpressionsEvaluator evalExpr = ExpressionsFactory.create("2+3*4-6/2");  
  assertEquals(BigDecimal.valueOf(11), evalExpr.eval()); 

Ответ 11

Я думаю, что когда-нибудь вы это сделаете, это будет связано с множеством условных утверждений. Но для одиночных операций, например, в ваших примерах, вы можете ограничить это до 4 операторов с чем-то вроде

String math = "1+4";

if (math.split("+").length == 2) {
    //do calculation
} else if (math.split("-").length == 2) {
    //do calculation
} ...

Это становится намного сложнее, если вы хотите иметь дело с несколькими операциями типа "4 + 5 * 6".

Если вы пытаетесь построить калькулятор, я бы опрокидывал каждую секцию вычисления отдельно (каждый номер или оператор), а не как одну строку.

Ответ 12

Кажется, JEP должен выполнить задание

Ответ 13

если мы собираемся его реализовать, тогда мы сможем использовать приведенный ниже алгоритм: -

  • Пока есть еще токены для чтения,

    1.1. Получите следующий токен. 1.2 Если токен:

    1.2.1 Число: нажмите на стек значений.

    1.2.2 Переменная: получить ее значение и нажать на стек значений.

    1.2.3 Левая скобка: надавите на стек оператора.

    1.2.4 Прямая скобка:

     1 While the thing on top of the operator stack is not a 
       left parenthesis,
         1 Pop the operator from the operator stack.
         2 Pop the value stack twice, getting two operands.
         3 Apply the operator to the operands, in the correct order.
         4 Push the result onto the value stack.
     2 Pop the left parenthesis from the operator stack, and discard it.
    

    1.2.5 Оператор (назовите его thisOp):

     1 While the operator stack is not empty, and the top thing on the
       operator stack has the same or greater precedence as thisOp,
       1 Pop the operator from the operator stack.
       2 Pop the value stack twice, getting two operands.
       3 Apply the operator to the operands, in the correct order.
       4 Push the result onto the value stack.
     2 Push thisOp onto the operator stack.
    
  • Пока стек оператора не пуст, 1 Выполните посылку оператора из стека оператора. 2 Выполните дважды стек значений, получив два операнда. 3 Примените оператор к операндам в правильном порядке. 4 Нажмите результат на стек значений.

  • В этот момент стек оператора должен быть пустым, а значение стек должен иметь только одно значение, что является конечным результатом.

Ответ 14

Вы можете взглянуть на инфраструктуру Symja:

ExprEvaluator util = new ExprEvaluator(); 
IExpr result = util.evaluate("10-40");
System.out.println(result.toString()); // -> "-30" 

Обратите внимание, что можно определить более сложные выражения:

// D(...) gives the derivative of the function Sin(x)*Cos(x)
IAST function = D(Times(Sin(x), Cos(x)), x);
IExpr result = util.evaluate(function);
// print: Cos(x)^2-Sin(x)^2

Ответ 15

Это фактически дополняет ответ, данный @Boann. У этого есть небольшая ошибка, которая вызывает "-2 ^ 2", чтобы дать ошибочный результат -4.0. Проблема для этого - точка, в которой в его оценке оценивается степень возведения в степень. Просто переместите экспоненцию в блок parseTerm(), и все будет хорошо. Посмотрите ниже, что @Boann answer слегка изменено. Модификация в комментариях.

public static double eval(final String str) {
    return new Object() {
        int pos = -1, ch;

        void nextChar() {
            ch = (++pos < str.length()) ? str.charAt(pos) : -1;
        }

        boolean eat(int charToEat) {
            while (ch == ' ') nextChar();
            if (ch == charToEat) {
                nextChar();
                return true;
            }
            return false;
        }

        double parse() {
            nextChar();
            double x = parseExpression();
            if (pos < str.length()) throw new RuntimeException("Unexpected: " + (char)ch);
            return x;
        }

        // Grammar:
        // expression = term | expression `+` term | expression `-` term
        // term = factor | term `*` factor | term `/` factor
        // factor = `+` factor | `-` factor | `(` expression `)`
        //        | number | functionName factor | factor `^` factor

        double parseExpression() {
            double x = parseTerm();
            for (;;) {
                if      (eat('+')) x += parseTerm(); // addition
                else if (eat('-')) x -= parseTerm(); // subtraction
                else return x;
            }
        }

        double parseTerm() {
            double x = parseFactor();
            for (;;) {
                if      (eat('*')) x *= parseFactor(); // multiplication
                else if (eat('/')) x /= parseFactor(); // division
                else if (eat('^')) x = Math.pow(x, parseFactor()); //exponentiation -> Moved in to here. So the problem is fixed
                else return x;
            }
        }

        double parseFactor() {
            if (eat('+')) return parseFactor(); // unary plus
            if (eat('-')) return -parseFactor(); // unary minus

            double x;
            int startPos = this.pos;
            if (eat('(')) { // parentheses
                x = parseExpression();
                eat(')');
            } else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
                while ((ch >= '0' && ch <= '9') || ch == '.') nextChar();
                x = Double.parseDouble(str.substring(startPos, this.pos));
            } else if (ch >= 'a' && ch <= 'z') { // functions
                while (ch >= 'a' && ch <= 'z') nextChar();
                String func = str.substring(startPos, this.pos);
                x = parseFactor();
                if (func.equals("sqrt")) x = Math.sqrt(x);
                else if (func.equals("sin")) x = Math.sin(Math.toRadians(x));
                else if (func.equals("cos")) x = Math.cos(Math.toRadians(x));
                else if (func.equals("tan")) x = Math.tan(Math.toRadians(x));
                else throw new RuntimeException("Unknown function: " + func);
            } else {
                throw new RuntimeException("Unexpected: " + (char)ch);
            }

            //if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation -> This is causing a bit of problem

            return x;
        }
    }.parse();
}

Ответ 16

package ExpressionCalculator.expressioncalculator;

import java.text.DecimalFormat;
import java.util.Scanner;

public class ExpressionCalculator {

private static String addSpaces(String exp){

    //Add space padding to operands.
    //https://regex101.com/r/sJ9gM7/73
    exp = exp.replaceAll("(?<=[0-9()])[\\/]", " / ");
    exp = exp.replaceAll("(?<=[0-9()])[\\^]", " ^ ");
    exp = exp.replaceAll("(?<=[0-9()])[\\*]", " * ");
    exp = exp.replaceAll("(?<=[0-9()])[+]", " + "); 
    exp = exp.replaceAll("(?<=[0-9()])[-]", " - ");

    //Keep replacing double spaces with single spaces until your string is properly formatted
    /*while(exp.indexOf("  ") != -1){
        exp = exp.replace("  ", " ");
     }*/
    exp = exp.replaceAll(" {2,}", " ");

       return exp;
}

public static Double evaluate(String expr){

    DecimalFormat df = new DecimalFormat("#.####");

    //Format the expression properly before performing operations
    String expression = addSpaces(expr);

    try {
        //We will evaluate using rule BDMAS, i.e. brackets, division, power, multiplication, addition and
        //subtraction will be processed in following order
        int indexClose = expression.indexOf(")");
        int indexOpen = -1;
        if (indexClose != -1) {
            String substring = expression.substring(0, indexClose);
            indexOpen = substring.lastIndexOf("(");
            substring = substring.substring(indexOpen + 1).trim();
            if(indexOpen != -1 && indexClose != -1) {
                Double result = evaluate(substring);
                expression = expression.substring(0, indexOpen).trim() + " " + result + " " + expression.substring(indexClose + 1).trim();
                return evaluate(expression.trim());
            }
        }

        String operation = "";
        if(expression.indexOf(" / ") != -1){
            operation = "/";
        }else if(expression.indexOf(" ^ ") != -1){
            operation = "^";
        } else if(expression.indexOf(" * ") != -1){
            operation = "*";
        } else if(expression.indexOf(" + ") != -1){
            operation = "+";
        } else if(expression.indexOf(" - ") != -1){ //Avoid negative numbers
            operation = "-";
        } else{
            return Double.parseDouble(expression);
        }

        int index = expression.indexOf(operation);
        if(index != -1){
            indexOpen = expression.lastIndexOf(" ", index - 2);
            indexOpen = (indexOpen == -1)?0:indexOpen;
            indexClose = expression.indexOf(" ", index + 2);
            indexClose = (indexClose == -1)?expression.length():indexClose;
            if(indexOpen != -1 && indexClose != -1) {
                Double lhs = Double.parseDouble(expression.substring(indexOpen, index));
                Double rhs = Double.parseDouble(expression.substring(index + 2, indexClose));
                Double result = null;
                switch (operation){
                    case "/":
                        //Prevent divide by 0 exception.
                        if(rhs == 0){
                            return null;
                        }
                        result = lhs / rhs;
                        break;
                    case "^":
                        result = Math.pow(lhs, rhs);
                        break;
                    case "*":
                        result = lhs * rhs;
                        break;
                    case "-":
                        result = lhs - rhs;
                        break;
                    case "+":
                        result = lhs + rhs;
                        break;
                    default:
                        break;
                }
                if(indexClose == expression.length()){
                    expression = expression.substring(0, indexOpen) + " " + result + " " + expression.substring(indexClose);
                }else{
                    expression = expression.substring(0, indexOpen) + " " + result + " " + expression.substring(indexClose + 1);
                }
                return Double.valueOf(df.format(evaluate(expression.trim())));
            }
        }
    }catch(Exception exp){
        exp.printStackTrace();
    }
    return 0.0;
}

public static void main(String args[]){

    Scanner scanner = new Scanner(System.in);
    System.out.print("Enter an Mathematical Expression to Evaluate: ");
    String input = scanner.nextLine();
    System.out.println(evaluate(input));
}

}

Ответ 17

Попробуйте использовать следующий пример кода, используя JDK1.6 Javascript engine с обработкой впрыска кода.

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class EvalUtil {
private static ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
public static void main(String[] args) {
    try {
        System.out.println((new EvalUtil()).eval("(((5+5)/2) > 5) || 5 >3 "));
        System.out.println((new EvalUtil()).eval("(((5+5)/2) > 5) || true"));
    } catch (Exception e) {
        e.printStackTrace();
    }
}
public Object eval(String input) throws Exception{
    try {
        if(input.matches(".*[a-zA-Z;~`#$_{}\\[\\]:\\\\;\"',\\.\\?]+.*")) {
            throw new Exception("Invalid expression : " + input );
        }
        return engine.eval(input);
    } catch (Exception e) {
        e.printStackTrace();
        throw e;
    }
 }
}

Ответ 18

import java.util.*;
StringTokenizer st;
int ans;

public class check { 
   String str="7 + 5";
   StringTokenizer st=new StringTokenizer(str);

   int v1=Integer.parseInt(st.nextToken());
   String op=st.nextToken();
   int v2=Integer.parseInt(st.nextToken());

   if(op.equals("+")) { ans= v1 + v2; }
   if(op.equals("-")) { ans= v1 - v2; }
   //.........
}

Ответ 19

Как насчет чего-то вроде этого:

String st = "10+3";
int result;
for(int i=0;i<st.length();i++)
{
  if(st.charAt(i)=='+')
  {
    result=Integer.parseInt(st.substring(0, i))+Integer.parseInt(st.substring(i+1, st.length()));
    System.out.print(result);
  }         
}

и делать то же самое для каждого другого математического оператора соответственно.

Ответ 20

Можно преобразовать любую строку выражения в нотацию infix в постфиксную нотацию, используя алгоритм shink-yard Djikstra. Результат алгоритма затем может служить входом в постфиксный алгоритм с возвратом результата выражения.

Я написал статью об этом здесь, с реализацией в java

Ответ 21

Слишком поздно ответить, но я столкнулся с той же ситуацией, чтобы оценить выражение в java, это может помочь кому-то

MVEL выполняет вычисления времени выполнения, мы можем написать java-код в String, чтобы получить его в этом.

    String expressionStr = "x+y";
    Map<String, Object> vars = new HashMap<String, Object>();
    vars.put("x", 10);
    vars.put("y", 20);
    ExecutableStatement statement = (ExecutableStatement) MVEL.compileExpression(expressionStr);
    Object result = MVEL.executeExpression(statement, vars);

Ответ 22

Еще один вариант: https://github.com/stefanhaustein/expressionparser

Я реализовал это, чтобы иметь простой, но гибкий вариант, позволяющий обоим:

Связанный выше TreeBuilder является частью демонстрационного пакета CAS, который выполняет символический вывод. Существует также BASIC interpreter, и я начал создавать TypeScript интерпретатор, используя его.

Ответ 23

Для запуска javascript можно использовать внешнюю библиотеку, такую ​​как RHINO или NASHORN. И javascript может оценивать простую формулу без парсинга строки. Не влияет на производительность, если код написан хорошо. Ниже приведен пример с RHINO -

public class RhinoApp {
    private String simpleAdd = "(12+13+2-2)*2+(12+13+2-2)*2";

public void runJavaScript() {
    Context jsCx = Context.enter();
    Context.getCurrentContext().setOptimizationLevel(-1);
    ScriptableObject scope = jsCx.initStandardObjects();
    Object result = jsCx.evaluateString(scope, simpleAdd , "formula", 0, null);
    Context.exit();
    System.out.println(result);
}

Ответ 24

Класс Java, который может вычислять математические выражения:

package test;

public class Calculator {

    public static Double calculate(String expression){
        if (expression == null || expression.length() == 0) {
            return null;
        }
        return calc(expression.replace(" ", ""));
    }
    public static Double calc(String expression) {

        if (expression.startsWith("(") && expression.endsWith(")")) {
            return calc(expression.substring(1, expression.length() - 1));
        }
        String[] containerArr = new String[]{expression};
        double leftVal = getNextOperand(containerArr);
        expression = containerArr[0];
        if (expression.length() == 0) {
            return leftVal;
        }
        char operator = expression.charAt(0);
        expression = expression.substring(1);

        while (operator == '*' || operator == '/') {
            containerArr[0] = expression;
            double rightVal = getNextOperand(containerArr);
            expression = containerArr[0];
            if (operator == '*') {
                leftVal = leftVal * rightVal;
            } else {
                leftVal = leftVal / rightVal;
            }
            if (expression.length() > 0) {
                operator = expression.charAt(0);
                expression = expression.substring(1);
            } else {
                return leftVal;
            }
        }
        if (operator == '+') {
            return leftVal + calc(expression);
        } else {
            return leftVal - calc(expression);
        }

    }

    private static double getNextOperand(String[] exp){
        double res;
        if (exp[0].startsWith("(")) {
            int open = 1;
            int i = 1;
            while (open != 0) {
                if (exp[0].charAt(i) == '(') {
                    open++;
                } else if (exp[0].charAt(i) == ')') {
                    open--;
                }
                i++;
            }
            res = calc(exp[0].substring(1, i - 1));
            exp[0] = exp[0].substring(i);
        } else {
            int i = 1;
            if (exp[0].charAt(0) == '-') {
                i++;
            }
            while (exp[0].length() > i && isNumber((int) exp[0].charAt(i))) {
                i++;
            }
            res = Double.parseDouble(exp[0].substring(0, i));
            exp[0] = exp[0].substring(i);
        }
        return res;
    }


    private static boolean isNumber(int c) {
        int zero = (int) '0';
        int nine = (int) '9';
        return (c >= zero && c <= nine) || c =='.';
    }

    public static void main(String[] args) {
        System.out.println(calculate("(((( -6 )))) * 9 * -1"));
        System.out.println(calc("(-5.2+-5*-5*((5/4+2)))"));

    }

}

Ответ 25

public class StringCalculator {

    public static void main(String[] args) {

        String eval = "2+3*2/2+2*5/5*5";

        System.out.println(calculator(eval));
    }

    public static int calcMulAndDiv(String val){

        String nos[] = val.split("\\D+");
        String opr[] = val.split("\\d+");
        int res = Integer.parseInt(nos[0]);

        for(int i = 1; i< opr.length ;i++){

            if(opr[i].equals("*")){
                res = res * Integer.parseInt(nos[i]);
            }
            else if(opr[i].equals("/")){
                res = res / Integer.parseInt(nos[i]);
            }

        }

        return res;
    }

    public static int calculator(String val){

        String nos[] = val.split("[+-]");
        String operators = val.replaceAll("[^+-]","");
        char opr[] = operators.toCharArray();
        int result = 0;

        if(nos[0].contains("*") || nos[0].contains("*")){
            result = calcMulAndDiv(nos[0]);
        }else{
            result = Integer.parseInt(nos[0]);
        }

        for(int i = 0 ; i < opr.length ; i++){

            if(opr[i] == '+'){
                if(nos[i+1].contains("*") || nos[i+1].contains("*")){
                    result = result + calcMulAndDiv(nos[i+1]);
                }else{
                    result = result + Integer.parseInt(nos[i+1]);
                }
            }
            else if(opr[i] == '-'){
                if(nos[i+1].contains("*") || nos[i+1].contains("*")){
                    result = result + calcMulAndDiv(nos[i+1]);
                }else{
                    result = result - Integer.parseInt(nos[i+1]);
                }
            }

        }

        return result;
    }
}

Ответ 26

public static void main(String[] args){   
    System.out.println("="+evaluate(args[2]));

}
public static String[] symbols = new String[]{"\\-","\\+","\\/","\\*"};

public static Integer evaluate(String exp){
    System.out.print(exp);
    exp = exp.trim(); 
    boolean isint = true;
    for(int i = 0; i<exp.length() && isint;i++){
        if(exp.charAt(i)>'9' || exp.charAt(i) <'0'){
            isint = false;
        }
    }
    if(isint) return Integer.parseInt(exp);

    for(String symbol:symbols){
        String[] split = exp.split(symbol);
        if(split.length>1){
            int ev = evaluate(split[0]);
            for(int i = 1;i<split.length;i++){
                System.out.print(symbol);
                int val = evaluate(split[i]);
                if("\\*".equals(symbol)) ev*=val;
                if("\\/".equals(symbol)) ev/=val;
                if("\\+".equals(symbol)) ev+=val;
                if("\\-".equals(symbol)) ev-=val;
            }
            return ev;
        }
    }
    return null;
}