Я намагаюся написати процедуру Java для оцінки простих математичних виразів із String
таких значень, як:
"5+3"
"10-40"
"10*3"
Я хочу уникати багатьох тверджень як тоді. Як я можу це зробити?
Я намагаюся написати процедуру Java для оцінки простих математичних виразів із String
таких значень, як:
"5+3"
"10-40"
"10*3"
Я хочу уникати багатьох тверджень як тоді. Як я можу це зробити?
Відповіді:
З 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 (що правильно)
Аналізатор є рекурсивним аналізатором зниження , тому внутрішньо використовує окремі методи розбору для кожного рівня пріоритетності оператора у своїй граматиці. Я це зберігав коротко, тому його легко змінити, але ось декілька ідей, з якими ви можете розширити:
Змінні:
Біт аналізатора, який читає імена для функцій, легко змінюється і для обробки спеціальних змінних, шукаючи імена в таблиці змінних, переданій в eval
методу, наприклад a 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, якщо одно повернення істинний і переміщує курсор до наступного символу, я використовую ім'я «прийняти» для нього.
Правильний спосіб вирішити це за допомогою лексеру та аналізатора . Ви можете самостійно писати прості версії, або на цих сторінках також є посилання на лексеми та парсери Java.
Створення рекурсивного аналізатора спуску - це дійсно гарна вправа.
Для свого університетського проекту я шукав аналізатор / оцінювач, що підтримує як основні формули, так і складніші рівняння (особливо ітераційні оператори). Я знайшов дуже гарну бібліотеку з відкритим кодом для JAVA та .NET під назвою mXparser. Я наведу кілька прикладів, щоб відчути синтаксис, для подальших інструкцій відвідайте веб-сайт проекту (особливо підручник).
https://mathparser.org/mxparser-tutorial/
І кілька прикладів
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.
З повагою
ТУТ - ще одна бібліотека з відкритим кодом на GitHub під назвою EvalEx.
На відміну від двигуна JavaScript, ця бібліотека зосереджена лише на оцінці математичних виразів. Більше того, бібліотека розширюється і підтримує використання булевих операторів, а також дужок.
Ви також можете спробувати перекладача BeanShell :
Interpreter interpreter = new Interpreter();
interpreter.eval("result = (7+21*6)/(32-27)");
System.out.println(interpreter.get("result"));
Ви можете легко оцінити вирази, якщо ваша програма Java вже має доступ до бази даних, не використовуючи жодних інших JAR.
У деяких базах даних потрібно використовувати макетну таблицю (наприклад, "подвійну" таблицю Oracle), а інші дозволять оцінити вирази, не "вибираючи" жодної таблиці.
Наприклад, на сервері Sql або Sqlite
select (((12.10 +12.0))/ 233.0) amount
і в Oracle
select (((12.10 +12.0))/ 233.0) amount from dual;
Перевага використання БД полягає в тому, що ви можете одночасно оцінювати багато виразів. Також більшість БД дозволять використовувати дуже складні вирази, а також матимуть ряд додаткових функцій, які можна викликати за необхідності.
Однак продуктивність може постраждати, якщо багато окремих виразів потрібно оцінювати індивідуально, особливо коли БД розташована на мережевому сервері.
Далі у певній мірі розглядається проблема продуктивності, використовуючи базу даних у пам'яті Sqlite.
Ось повний робочий приклад на Java
Class. forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection("jdbc:sqlite::memory:");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery( "select (1+10)/20.0 amount");
rs.next();
System.out.println(rs.getBigDecimal(1));
stat.close();
conn.close();
Звичайно, ви можете розширити вищевказаний код, щоб обробляти кілька обчислень одночасно.
ResultSet rs = stat.executeQuery( "select (1+10)/20.0 amount, (1+100)/20.0 amount2");
У цій статті розглядаються різні підходи. Ось два ключові підходи, згадані у статті:
Дозволяє для сценаріїв, що містять посилання на об'єкти 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 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 тут, а повні документи тут
якщо ми збираємось його реалізувати, тоді ми можемо використовувати алгоритм, наведений нижче:
Хоча ще є лексеми для читання,
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 Оператор (назвіть цеOp):
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());
Я думаю, що будь-коли, як ви це зробите, це матиме багато умовних тверджень. Але для одиночних операцій, як у ваших прикладах, ви можете обмежити її до 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
Спробуйте наступний зразок коду за допомогою механізму 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;
}
}
}
Це фактично доповнює відповідь, дану @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^2 = -4
насправді це нормально, а не помилка. Вона стає згрупованою, як -(2^2)
. Спробуйте, наприклад, на Десмосі. Ваш код фактично вводить кілька помилок. Перший полягає в тому, що ^
більше не групуються справа наліво. Іншими словами, 2^3^2
слід вважати групу подобається 2^(3^2)
тому, що ^
є правильною асоціацією, але ваші модифікації роблять її подібною до групи (2^3)^2
. Друга полягає в тому, що ^
вона має вищу перевагу перед *
та /
, але ваші модифікації трактують її так само. Див. Ideone.com/iN2mMa .
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);
}
}
і відповідно зробіть те ж саме для кожного іншого математичного оператора.
Можна перетворити будь-який рядок вираження в нотації інфіксації в нотацію постфікса, використовуючи алгоритм маневрового двору Джикстра . Результат алгоритму може служити вхідним кодом до алгоритму постфікса з поверненням результату вираження.
Я написав статтю про це тут, з реалізацією в 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, може використовуватися для запуску javascript. І 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 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; }
//.........
}