sourcecode

문자열 형식으로 주어진 수학 식을 어떻게 평가합니까?

copyscript 2022. 8. 31. 22:47
반응형

문자열 형식으로 주어진 수학 식을 어떻게 평가합니까?

의 식을 을 쓰려고 String다음 중 하나:

  1. "5+3"
  2. "10-40"
  3. "(1+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 `(` expression `)` | 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();
                if (!eat(')')) throw new RuntimeException("Missing ')'");
            } 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);
                if (eat('(')) {
                    x = parseExpression();
                    if (!eat(')')) throw new RuntimeException("Missing ')' after argument to " + func);
                } else {
                    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();
      }
    

    " 를 "하려면 "eval" "parse"를 반환하는 합니다.double그 대신 그 인터페이스의 인스턴스를 반환합니다.자바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 및 JAVA용 오픈소스 라이브러리는 매우 훌륭했습니다.MXparser라는 이름의 NET.구문에 대한 느낌을 살리기 위해 몇 가지 예를 들겠습니다. 자세한 설명은 프로젝트 웹사이트(특히 튜토리얼 섹션)를 참조하십시오.

https://mathparser.org/

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

https://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()

최근에 발견 - 구문을 사용해 보고 싶은 경우(및 고급 사용 사례 참조) mXparser를 탑재한 Scalar Calculator 을 다운로드할 수 있습니다.

이 문제를 해결하는 올바른 방법은 렉서파서를 사용하는 것입니다.이러한 페이지의 간단한 버전을 직접 작성할 수도 있고, Java 렉서 및 파서에 대한 링크도 있습니다.

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

여기에는 EvalEx라는 이름의 GitHub의 또 다른 오픈 소스 라이브러리는 GitHub에 있습니다.

JavaScript 엔진과 달리 이 라이브러리는 수학식만 평가하는 데 중점을 두고 있습니다.또한 라이브러리는 확장 가능하며 괄호뿐만 아니라 부울 연산자의 사용을 지원합니다.

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

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

예를 들어 SQL 서버 또는 SQLite에서

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

및 Oracle에서

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

다른 방법은 스프링식 언어(Spring Expression Language)를 사용하는 것입니다.스펠은 수학식 평가와 함께 훨씬 더 많은 것을 하기 때문에 약간 과잉일 수 있습니다.이 표현식 라이브러리는 독립 실행형이므로 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

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

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에 내장된 Javascript 엔진을 사용합니다.

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

구현하려면 다음 알고리즘을 사용할 수 있습니다.--

  1. 아직 읽을 토큰이 있는 동안

    1.1 다음 토큰을 가져옵니다. 1.2 토큰이 다음과 같은 경우:

    1.2.1 A 숫자: 값 스택에 푸시합니다.

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

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

사용법은 매우 간단하며, 다음과 같이 작업을 완료합니다.

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

JEP가 그 일을 해야 할 것 같다.

대답하기엔 너무 늦었지만 자바 표현법을 평가하기 위해 같은 상황을 만났는데, 누군가 도움이 될 수 있습니다.

MVEL 평가를 하려면 , 「자바 코드」를 사용합니다. 을 사용하다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);

어떤 식으로 하든 많은 조건들이 수반될 것입니다.그러나 예시와 같은 단일 작업의 경우 다음과 같은 문장이 포함된 경우 4로 제한할 수 있습니다.

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

}

import java.util.*;

public class check { 
   int ans;
   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; }
   //.........
}

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

    }

}

이런 건 어때?

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의 션팅 야드 알고리즘을 사용하여 infix 표기의 식 문자열을 postfix 표기로 변환할 수 있습니다.알고리즘의 결과는 식 결과를 반환하는 포스트픽스알고리즘에 대한 입력으로 기능할 수 있습니다.

여기에 java로 구현하여 기사를 작성했습니다.

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

심플하지만 유연한 옵션을 제공하여 다음 두 가지를 모두 가능하게 하기 위해 이를 구현했습니다.

위에 링크된 TreeBuilder는 심볼 파생 기능을 수행하는 CAS 데모 패키지의 일부입니다.BASIC 인터프리터의 예도 있고, 그것을 이용한 TypeScript 인터프리터 구축을 시작했습니다.

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);
}
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class test2 {
    public static void main(String[] args) throws ScriptException {
        String s = "10+2";
        ScriptEngineManager mn = new ScriptEngineManager();
        ScriptEngine en = mn.getEngineByName("js");
        Object result = en.eval(s);
        System.out.println(result);
    }
}

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

반응형