다음 String
과 같은 값 에서 간단한 수학 표현식을 평가하기 위해 Java 루틴을 작성하려고합니다 .
"5+3"
"10-40"
"10*3"
나는 많은 if-then-else 진술을 피하고 싶습니다. 어떻게해야합니까?
다음 String
과 같은 값 에서 간단한 수학 표현식을 평가하기 위해 Java 루틴을 작성하려고합니다 .
"5+3"
"10-40"
"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));
}
}
return (Double) engine.eval(foo);
new javax.script.ScriptEngineManager().getEngineByName("JavaScript") .eval("var f = new java.io.FileWriter('hello.txt'); f.write('UNLIMITED POWER!'); f.close();");
기본적으로 프로그램의 현재 디렉토리에 JavaScript를 통해 파일을
나는 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();
}
이제 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
하여 실제 프로그래밍 언어와 마찬가지로 식에 여러 데이터 유형을 혼합하여 사용할 수 있습니다. :)
이 답변의 모든 코드 는 공개 도메인에 릴리스되었습니다 . 즐기세요!
double x = parseTerm();
한 후 왼쪽 연산자를 평가합니다 for (;;) {...}
. 동일한 논리가 parseTerm 메소드에 있습니다. parseFactor에는 다음 레벨이 없으므로 메소드 / 변수의 평가 만 있거나 마비의 경우 하위 표현식을 평가합니다. 이 boolean eat(int charToEat)
메소드는 charToEat 문자와 현재 커서 문자의 동등성을 확인하고, true를 리턴하고 커서를 다음 문자로 이동하면 이름에 'accept'를 사용합니다.
이것을 해결하는 올바른 방법은 렉서 와 파서를 사용하는 것 입니다. 간단한 버전을 직접 작성하거나 해당 페이지에도 Java 렉서 및 구문 분석기에 대한 링크가 있습니다.
재귀 강하 파서를 만드는 것은 정말 좋은 학습 연습입니다.
대학 프로젝트에서 기본 수식과 더 복잡한 수식 (특히 반복 연산자)을 모두 지원하는 파서 / 평가자를 찾고있었습니다. mXparser라는 JAVA 및 .NET에 대한 매우 훌륭한 오픈 소스 라이브러리를 찾았습니다. 구문에 대한 느낌을주는 몇 가지 예를 제공 할 것입니다. 자세한 지침은 프로젝트 웹 사이트 (특히 자습서 섹션)를 방문하십시오.
https://mathparser.org/mxparser-tutorial/
그리고 몇 가지 예
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 엔진과 달리이 라이브러리는 수학 표현식 만 평가하는 데 중점을 둡니다. 또한 라이브러리는 확장 가능하며 부울 연산자와 괄호 사용을 지원합니다.
BeanShell 인터프리터를 사용해 볼 수도 있습니다 .
Interpreter interpreter = new Interpreter();
interpreter.eval("result = (7+21*6)/(32-27)");
System.out.println(interpreter.get("result"));
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");
이 기사 에서는 다양한 접근 방식에 대해 설명합니다. 이 기사에서 언급 한 두 가지 주요 접근 방식은 다음과 같습니다.
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);
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
구현하려는 경우 아래 알고리즘을 사용할 수 있습니다.
읽을 토큰이 여전히 있지만,
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.
운영자 스택이 비어 있지 않은 경우 1 운영자 스택에서 운영자를 팝합니다. 2 값 스택을 두 번 팝하여 두 피연산자를 얻습니다. 3 피연산자에 올바른 순서로 연산자를 적용하십시오. 4 결과를 값 스택으로 밉니다.
이 시점에서 연산자 스택은 비어 있어야하며 값 스택에는 값이 하나만 있어야합니다. 이것이 최종 결과입니다.
이것은 또 다른 흥미로운 대안입니다 https://github.com/Shy-Ta/expression-evaluator-demo
사용법은 매우 간단하고 작업을 완료합니다 (예 :
ExpressionsEvaluator evalExpr = ExpressionsFactory.create("2+3*4-6/2");
assertEquals(BigDecimal.valueOf(11), evalExpr.eval());
나는 당신이 이것을하는 방법이 많은 조건문을 포함 할 것이라고 생각합니다. 그러나 예제에서와 같은 단일 작업의 경우 다음과 같은 경우가있는 if 문을 4 개로 제한 할 수 있습니다
String math = "1+4";
if (math.split("+").length == 2) {
//do calculation
} else if (math.split("-").length == 2) {
//do calculation
} ...
"4 + 5 * 6"과 같은 여러 작업을 처리하려는 경우 훨씬 더 복잡해집니다.
계산기를 만들려고하면 계산의 각 섹션을 단일 문자열이 아닌 개별적으로 (각 숫자 또는 연산자) 전달하는 것이 가장 좋습니다.
대답하기에는 너무 늦었지만 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);
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();
}
-2^2 = -4
실제로는 정상이며 버그가 아닙니다. 처럼 그룹화됩니다 -(2^2)
. 예를 들어 Desmos에서 사용해보십시오. 실제로 코드에는 몇 가지 버그가 있습니다. 첫 번째는 ^
더 이상 오른쪽에서 왼쪽으로 그룹화하지 않는 것입니다. 다시 말해서, 오른쪽 연관 이기 때문에 2^3^2
같은 것으로 그룹화되어야 하지만 수정하면 그룹처럼 됩니다. 두 번째는 and 보다 우선 순위가 높지만 수정 내용이 동일하게 취급된다는 것입니다. ideone.com/iN2mMa를 참조하십시오 . 2^(3^2)
^
(2^3)^2
^
*
/
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));
}
}
이런 식으로 어떻습니까 :
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로 구현 된 기사를 썼습니다.
또 다른 옵션 : https://github.com/stefanhaustein/expressionparser
간단하지만 유연한 옵션으로 두 가지를 모두 허용하도록 이것을 구현했습니다.
위에 링크 된 TreeBuilder 는 기호 파생을 수행 하는 CAS 데모 패키지의 일부입니다 . BASIC 인터프리터 예제 도 있으며 이를 사용하여 TypeScript 인터프리터 를 빌드하기 시작 했습니다.
수학 표현식을 평가할 수있는 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)))"));
}
}
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);
}
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; }
//.........
}