Могу ли я преобразовать из строки в int даже со специальными символами? [Дубликат]

Я столкнулся с той же проблемой. Ни одно из вышеупомянутых предложений не работало для меня. Тем не менее, я решил это, объяснив, вызывая picker.dismiss и увольнять пост, что. Я не совсем понимаю, почему я вызываю подобные вызовы, но это сработало для меня.

   @objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

        print("Image picked")
        picker.dismiss(animated: true, completion: nil)
        dismiss(animated: true) {
            print("dismissed")
             self.delegate?.presentEditor(img: (info[UIImagePickerControllerOriginalImage] as? UIImage)!, id: self.id!)
    }

}
262
задан Francesco Menzani 20 September 2015 в 14:17
поделиться

25 ответов

С 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));
    } 
}
320
ответ дан Abdull 23 August 2018 в 00:41
поделиться
  • 1
    Кажется, там есть большая проблема; Он выполняет скрипт, не оценивает выражение. Чтобы быть ясным, engine.eval («8; 40 + 2») выдает 42! Если вам нужен синтаксис выражений, который также проверяет синтаксис, я только что закончил один (потому что я не нашел ничего, что соответствовало моим потребностям): Javaluator . – Jean-Marc Astesana 29 August 2012 в 13:33
  • 2
    В качестве побочного примечания, если вам нужно использовать результат этого выражения в другом месте вашего кода, вы можете придать результат двойному: return (Double) engine.eval(foo); – Ben Visness 2 April 2014 в 23:44
  • 3
    Примечание по безопасности: вы никогда не должны использовать это в контексте сервера с пользовательским вводом. Выполненный JavaScript может получить доступ ко всем классам Java и, таким образом, захватить ваше приложение без ограничений. – Boann 21 September 2015 в 11:08
  • 4
    @Boann, я прошу вас дать мне ссылку о том, что вы сказали (на 100%) – partho 27 February 2016 в 14:03
  • 5
    @partho new javax.script.ScriptEngineManager().getEngineByName("JavaScript") .eval("var f = new java.io.FileWriter('hello.txt'); f.write('UNLIMITED POWER!'); f.close();"); - напишет файл через JavaScript в (по умолчанию) текущий каталог программы – Boann 27 February 2016 в 14:37
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;
    }
}
-2
ответ дан Arpan 23 August 2018 в 00:41
поделиться
  • 1
    Не корректно обрабатывает приоритет оператора. Существуют стандартные способы сделать это, и это не один из них. – user207421 17 April 2018 в 02:09

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

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 отлично подходит для этого. Пример одного из измененных методов:
    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, позволяя смешивать типы данных в выражениях, как и в реальном языке программирования. :)

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

171
ответ дан Boann 23 August 2018 в 00:41
поделиться
  • 1
    Спасла мне кучу горячего беспорядка. Большое спасибо. & Lt; 3 – php_coder_3809625 30 April 2016 в 09:08
  • 2
    Хороший алгоритм, начиная с него, мне удалось внедрить и логические операторы. Мы создали отдельные классы для функций для оценки функции, поэтому, подобно вашей идее переменных, я создаю карту с функциями и заботясь о имени функции. Каждая функция реализует интерфейс с помощью метода eval (T rightOperator, T leftOperator), поэтому в любое время мы можем добавлять функции без изменения кода алгоритма. И это хорошая идея, чтобы он работал с родовыми типами. Спасибо вам! – Vasile Bors 23 July 2016 в 16:17
  • 3
    Можете ли вы объяснить логику этого алгоритма? – iYonatan 24 July 2016 в 00:06
  • 4
    Я пытаюсь дать описание того, что я понимаю из кода, написанного Боанном, и примеры, описанные wiki. Логика этого алгоритма, начиная с правил операций. 1. знак оператора | переменная оценка | вызов функции | скобки (подвыражения); 2. возведение в степень; 3. умножение, деление; 4. сложение, вычитание; – Vasile Bors 24 July 2016 в 15:05
  • 5
    Методы алгоритма делятся для каждого уровня порядка операций следующим образом: parseFactor = 1. знак оператора | переменная оценка | вызов функции | скобки (подвыражения); 2. возведение в степень; parseTerms = 3. умножение, деление; parseExpression = 4. сложение, вычитание. Алгоритм, методы вызова в обратном порядке (parseExpression - & gt; parseTerms - & gt; parseFactor - & gt; parseExpression (для подвыражений)), но каждый метод в первой строке вызывает метод на следующий уровень, поэтому весь порядок выполнения методы будут фактически нормальным порядком операций. – Vasile Bors 24 July 2016 в 15:09

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

5
ответ дан Bozho 23 August 2018 в 00:41
поделиться

В этой статье указаны три разных подхода, один из которых - JEXL из Apache и позволяет сценарии, содержащие ссылки на java-объекты.

7
ответ дан Brad Parks 23 August 2018 в 00:41
поделиться
  • 1
    Просьба обобщить информацию из статьи, если ссылка на нее нарушена. – DJClayworth 11 October 2016 в 15:53

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

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;
    }
 }
}
2
ответ дан Bruce 23 August 2018 в 00:41
поделиться

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

String math = "1+4";

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

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

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

5
ответ дан BruteForce 23 August 2018 в 00:41
поделиться
  • 1
    Это становится намного сложнее, как только вам приходится иметь дело с несколькими операциями, приоритетом оператора, круглыми скобками ... на самом деле все, что характеризует реальное арифметическое выражение. Вы не можете попасть туда, начиная с этой техники. – user207421 16 June 2016 в 03:52

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

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();
}
2
ответ дан Community 23 August 2018 в 00:41
поделиться
  • 1
    -2^2 = -4 на самом деле нормальный, а не ошибка. Он группируется как -(2^2). Попробуйте, например, на Desmos. Ваш код действительно вводит несколько ошибок. Во-первых, ^ больше не группируется справа налево. Другими словами, 2^3^2 предполагается группировать как 2^(3^2), потому что ^ является право-ассоциативным, но ваши модификации делают его похожим на (2^3)^2. Во-вторых, предполагается, что ^ имеет более высокий приоритет, чем * и /, но ваши модификации относятся к нему одинаково. См. ideone.com/iN2mMa . – Radiodef 16 August 2018 в 01:06
  • 2
    Итак, что вы предлагаете, так это то, что возведение в степень лучше держаться там, где это было, не так ли? – Romeo Sierra 16 August 2018 в 05:27
  • 3
    Да, это то, что я предлагаю. – Radiodef 16 August 2018 в 15:07

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

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

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

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

и в Oracle

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

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

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

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

Вот полный рабочий пример в 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");
12
ответ дан DAB 23 August 2018 в 00:41
поделиться
  • 1
    Поздороваться с SQL-инъекцией! – cyberz 23 April 2017 в 19:53
  • 2
    Это зависит от того, для чего вы используете БД. Если вы хотите быть уверенным, вы можете легко создать пустую базу данных sqlite, особенно для оценки математики. – DAB 24 April 2017 в 15:06
  • 3
    @cyberz Если вы используете мой пример выше, Sqlite создаст временную БД в памяти. См. stackoverflow.com/questions/849679/… – DAB 24 April 2017 в 15:09
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; }
   //.........
}
1
ответ дан developer033 23 August 2018 в 00:41
поделиться

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

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

1
ответ дан Emmanuel John 23 August 2018 в 00:41
поделиться

Еще один способ - использовать Spring Expression Language или SpEL, который делает намного больше, а также оценивает математические выражения, поэтому может немного переборщить. Вам не нужно использовать Spring framework для использования этой библиотеки выражений, поскольку она является автономной. Копирование примеров из документации 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 здесь и полные документы здесь

6
ответ дан Faheem Sohail 23 August 2018 в 00:41
поделиться

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

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

25
ответ дан Greg Hewgill 23 August 2018 в 00:41
поделиться

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

http://mathparser.org/ / g4]

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

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

9
ответ дан HoldOffHunger 23 August 2018 в 00:41
поделиться

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

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

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

1
ответ дан keyser 23 August 2018 в 00:41
поделиться
  • 1
    Вы должны прочитать о написании эффективных синтаксических выражений математического выражения. Для этого есть методология компьютерной науки. Посмотрите, например, на ANTLR. Если вы хорошо думаете о том, что вы написали, вы увидите, что такие вещи, как (a + b / -c) * (e / f), не будут работать с вашей идеей, или код будет супер-пупер грязным и неэффективным. – Daniel Nuriyev 24 April 2014 в 19:03
  • 2
    Это хуже, чем заявление оператора switch ... – programmers5 14 November 2015 в 20:40

Вы можете взглянуть на структуру 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
3
ответ дан Laurent Magnin 23 August 2018 в 00:41
поделиться

Для запуска 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);
}
1
ответ дан Manish 23 August 2018 в 00:41
поделиться

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

Interpreter interpreter = new Interpreter();
interpreter.eval("result = (7+21*6)/(32-27)");
System.out.println(interpreter.get("result"));
12
ответ дан marciowerner 23 August 2018 в 00:41
поделиться

Класс 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)))"));

    }

}
0
ответ дан MultiplyByZer0 23 August 2018 в 00:41
поделиться
  • 1
    Не корректно обрабатывает приоритет оператора. Существуют стандартные способы сделать это, и это не один из них. – user207421 17 April 2018 в 02:08
  • 2
    EJP, можете ли вы указать, где есть проблема с приоритетом оператора? я полностью согласен с тем, что это не стандартный способ сделать это. стандартные способы уже упоминались в предыдущих сообщениях, идея заключалась в том, чтобы показать другой способ сделать это. – Efi G 22 April 2018 в 07:30

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

  1. Пока еще есть токены для чтения, 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.
    
  2. Пока стек оператора не пуст, 1 Выполните посылку оператора из стека оператора. 2 Выполните дважды стек значений, получив два операнда. 3 Примените оператор к операндам в правильном порядке. 4 Нажмите результат в стек значений.
  3. В этот момент стек оператора должен быть пустым, а стек значений должен иметь только одно значение, которое является конечным результатом.
5
ответ дан Prashant Gautam 23 August 2018 в 00:41
поделиться
  • 1
    Это некредитованное изложение алгоритма Dijkstra Shunting-yard . Кредит, в котором должен быть предоставлен кредит. – user207421 16 June 2016 в 03:51

Слишком поздно, чтобы ответить, но я столкнулся с такой же ситуацией, чтобы оценить выражение в 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);
1
ответ дан Saravana 23 August 2018 в 00:41
поделиться

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

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

  ExpressionsEvaluator evalExpr = ExpressionsFactory.create("2+3*4-6/2");  
  assertEquals(BigDecimal.valueOf(11), evalExpr.eval()); 
6
ответ дан Scorpion 23 August 2018 в 00:41
поделиться

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

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

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

1
ответ дан Stefan Haustein 23 August 2018 в 00:41
поделиться
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));
}

}

2
ответ дан Taher Khorshidi 23 August 2018 в 00:41
поделиться
  • 1
    Не обрабатывает приоритет оператора, несколько операторов или круглые скобки. Не используй. – user207421 18 July 2016 в 00:25

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

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

15
ответ дан Tanvir 23 August 2018 в 00:41
поделиться
  • 1
    Это нормально, но не удается, когда мы пытаемся умножить значения кратных 5 или 10, например 65 * 6 приводит к 3,9E + 2 ... – paarth batra 26 April 2018 в 08:09
  • 2
    . Но есть способ исправить это, отбросив его до int i.e. Int output = (int) 65 * 6, теперь будет 390 – paarth batra 26 April 2018 в 11:31
  • 3
    Чтобы уточнить, это не проблема библиотеки, а проблема с представлением чисел как значений с плавающей запятой. – DavidBittner 6 June 2018 в 15:52
Другие вопросы по тегам:

Похожие вопросы: