Programing

문자열 형식으로 주어진 수학 표현식을 평가하는 방법은 무엇입니까?

lottogame 2020. 3. 17. 08:32
반응형

문자열 형식으로 주어진 수학 표현식을 평가하는 방법은 무엇입니까? [닫은]


다음 String과 같은 값 에서 간단한 수학 표현식을 평가하기 위해 Java 루틴을 작성하려고합니다 .

  1. "5+3"
  2. "10-40"
  3. "10*3"

나는 많은 if-then-else 진술을 피하고 싶습니다. 어떻게해야합니까?


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

나는 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 (정확한)


파서는 재귀 하강 파서 이므로 내부적으로 문법에서 각 연산자 우선 순위에 대해 별도의 구문 분석 방법을 사용합니다. 수정하기 쉽도록 짧게 유지 했지만 다음과 같이 확장하려는 아이디어가 있습니다.

  • 변수:

    함수의 이름을 읽는 파서의 비트는 a eval와 같은 메소드에 전달 된 변수 테이블에서 이름을 찾아서 사용자 정의 변수를 처리하도록 쉽게 변경할 수 있습니다 Map<String,Double> variables.

  • 별도의 편집 및 평가 :

    변수에 대한 지원을 추가 한 후 매번 구문 분석하지 않고 변경된 변수로 동일한 표현식을 수백만 번 평가하려면 어떻게해야합니까? 있을 수있다. 먼저 사전 컴파일 된 표현식을 평가하는 데 사용할 인터페이스를 정의하십시오.

    @FunctionalInterface
    interface Expression {
        double eval();
    }
    

    이제 doubles 를 반환하는 모든 메서드를 변경 하여 대신 해당 인터페이스의 인스턴스를 반환합니다. 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하여 실제 프로그래밍 언어와 마찬가지로 표현식에 여러 데이터 유형을 혼합하여 사용할 수 있습니다. :)


이 답변의 모든 코드 는 공개 도메인에 릴리스되었습니다 . 즐기세요!


이것을 해결하는 올바른 방법은 렉서파서를 사용하는 것 입니다. 이 버전의 간단한 버전을 직접 작성하거나 해당 페이지에도 Java 렉서 및 구문 분석기에 대한 링크가 있습니다.

재귀 강하 파서를 만드는 것은 정말 좋은 학습 연습입니다.


대학 프로젝트에서 기본 수식과 더 복잡한 수식 (특히 반복 연산자)을 모두 지원하는 파서 / 평가자를 찾고있었습니다. mXparser라는 JAVA 및 .NET에 대한 매우 훌륭한 오픈 소스 라이브러리를 찾았습니다. 구문에 대한 느낌을주는 몇 가지 예를 제공 할 것입니다. 자세한 지침은 프로젝트 웹 사이트 (특히 자습서 섹션)를 방문하십시오.

http://mathparser.org/

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

http://mathparser.org/api/

그리고 몇 가지 예

1-단순 furmula

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

최근에 발견 – 구문을 사용하려는 경우 (고급 사용 사례 참조) mXparser가 제공하는 Scalar Calculator 다운로드 할 수 있습니다 .

친애하는


여기 EitEx라는 GitHub의 또 다른 오픈 소스 라이브러리입니다.

JavaScript 엔진과 달리이 라이브러리는 수학 표현식 만 평가하는 데 중점을 둡니다. 또한 라이브러리는 확장 가능하며 부울 연산자와 괄호 사용을 지원합니다.


Java 응용 프로그램이 다른 JAR을 사용하지 않고 이미 데이터베이스에 액세스하는 경우 표현식을 쉽게 평가할 수 있습니다.

일부 데이터베이스는 더미 테이블 (예 : Oracle의 "이중"테이블)을 사용해야하며 다른 데이터베이스에서는 테이블에서 "선택"하지 않고 식을 평가할 수 있습니다.

예를 들어 Sql Server 또는 Sqlite에서

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

오라클에서

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

DB를 사용하면 여러 식을 동시에 평가할 수 있다는 장점이 있습니다. 또한 대부분의 DB를 사용하면 매우 복잡한 표현식을 사용할 수 있으며 필요에 따라 호출 할 수있는 추가 기능이 많이 있습니다.

그러나 많은 단일 표현식을 개별적으로 평가해야하는 경우, 특히 DB가 네트워크 서버에있는 경우 성능이 저하 될 수 있습니다.

다음은 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");

BeanShell 인터프리터를 사용해 볼 수도 있습니다 .

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

이 기사 에서는 다양한 접근 방식에 대해 설명합니다. 이 기사에서 언급 한 두 가지 주요 접근 방식은 다음과 같습니다.

Apache의 JEXL

Java 객체에 대한 참조를 포함하는 스크립트를 허용합니다.

// Create or retrieve a JexlEngine
JexlEngine jexl = new JexlEngine();
// Create an expression object
String jexlExp = "foo.innerFoo.bar()";
Expression e = jexl.createExpression( jexlExp );

// Create a context and add data
JexlContext jctx = new MapContext();
jctx.set("foo", new Foo() );

// Now evaluate the expression, getting the result
Object o = e.evaluate(jctx);

JDK에 포함 된 자바 스크립트 엔진을 사용하십시오.

private static void jsEvalWithVariable()
{
    List<String> namesList = new ArrayList<String>();
    namesList.add("Jill");
    namesList.add("Bob");
    namesList.add("Laureen");
    namesList.add("Ed");

    ScriptEngineManager mgr = new ScriptEngineManager();
    ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");

    jsEngine.put("namesListKey", namesList);
    System.out.println("Executing in script environment...");
    try
    {
      jsEngine.eval("var x;" +
                    "var names = namesListKey.toArray();" +
                    "for(x in names) {" +
                    "  println(names[x]);" +
                    "}" +
                    "namesListKey.add(\"Dana\");");
    }
    catch (ScriptException ex)
    {
        ex.printStackTrace();
    }
}

또 다른 방법은 수학 표현 평가와 함께 훨씬 더 많은 기능을 수행하는 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 예제를 여기에서 읽고 전체 문서를 여기 에서 읽으 십시오


이것은 또 다른 흥미로운 대안입니다 https://github.com/Shy-Ta/expression-evaluator-demo

사용법은 매우 간단하고 작업을 완료합니다 (예 :

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

우리가 그것을 구현하려고한다면 우리는 아래 알고리즘을 사용할 수 있습니다 :

  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 연산자 (이것이라고 부르십시오) :

     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. 이 시점에서 연산자 스택은 비어 있어야하며 값 스택에는 값이 하나만 있어야합니다. 이것이 최종 결과입니다.


JEP 가 일을 해야하는 것처럼 보입니다.


나는 당신이 이것을하는 방법에 많은 조건문이 포함될 것이라고 생각합니다. 그러나 귀하의 예제와 같은 단일 작업의 경우 다음과 같은 경우가있는 경우

String math = "1+4";

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

"4 + 5 * 6"과 같은 여러 작업을 처리하려는 경우 훨씬 더 복잡해집니다.

계산기를 만들려고하면 계산의 각 섹션을 단일 문자열이 아닌 개별적으로 (각 숫자 또는 연산자) 전달하는 것이 가장 좋습니다.


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

코드 삽입 처리와 함께 JDK1.6의 Javascript 엔진을 사용하여 다음 샘플 코드를 사용해보십시오.

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

이것은 실제로 @Boann의 답변을 보완합니다. 약간의 버그가있어서 "-2 ^ 2"가 -4.0의 잘못된 결과를 낳습니다. 그 문제는 지수가 지수에서 평가되는 시점입니다. 지수를 parseTerm () 블록으로 옮기면 괜찮을 것입니다. @Boann의 답변이 약간 수정 된 아래를 살펴보십시오 . 수정 사항은 의견에 있습니다.

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

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

}


대답하기에는 너무 늦었지만 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);

이런 식으로 어떻습니까 :

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

그리고 다른 모든 수학적 연산자에 대해서도 비슷한 일을합니다.


Djikstra의 분로 야드 알고리즘을 사용하여 접두사 표기법의 표현식 문자열을 접미사 표기법으로 변환 할 수 있습니다. 그런 다음 알고리즘 의 결과는 표현식의 결과를 리턴하여 접미사 알고리즘 에 대한 입력으로 사용될 수 있습니다 .

여기에 Java로 구현 된 기사를 썼습니다.


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; }
   //.........
}

또 다른 옵션 : https://github.com/stefanhaustein/expressionparser

간단하지만 유연한 옵션으로 두 가지를 모두 허용하도록 이것을 구현했습니다.

위에 링크 된 TreeBuilder 는 기호 파생을 수행 하는 CAS 데모 패키지의 일부입니다 . BASIC 인터프리터 예제 도 있으며 이를 사용하여 TypeScript 인터프리터 를 빌드하기 시작 했습니다.


RHINO 또는 NASHORN과 같은 외부 라이브러리를 사용하여 자바 스크립트를 실행할 수 있습니다. 그리고 자바 스크립트는 문자열을 파싱하지 않고 간단한 수식을 평가할 수 있습니다. 코드를 잘 작성해도 성능에 영향을 미치지 않습니다. 아래는 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);
}

수학 표현식을 평가할 수있는 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)))"));

    }

}

참고 URL : https://stackoverflow.com/questions/3422673/how-to-evaluate-a-math-expression-given-in-string-form

반응형