Вроде все тесты что нашёл проходит. Рекурсия тоже есть...
package com.javarush.task.task34.task3404;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/*
Рекурсия для мат. выражения
*/
public class Solution {
public static void main(String[] args) {
Solution solution = new Solution();
solution.recurse("sin(2*(-5+1.5*4)+28)", 0); //expected output 0.5 6
// solution.recurse("-2^4", 0); // -16
// solution.recurse("-5+1.5*4", 0); //expected output 1 6
// solution.recurse("-51+1500.0/(113.5+23/2)*4", 0); //expected output -48 6
// solution.recurse("-5+2^10/((113.5+23/2)*2+6)", 0); //expected output -1 6
// solution.recurse("cos(-5+2^10/((113.5+23/2)*2+6)*sin(90)+181)", 0); //expected output -1 6
// solution.recurse("-1.5*4", 0); //expected output -6 6
// solution.recurse("sin(2*(-5+1.5*4)+28)", 0); //expected output 0.5 6
// solution.recurse("tan(2025^0.5)", 0); //expected output 1 2
// solution.recurse("1+(1+(1+1)*(1+1))*(1+1)+1", 0); // 12 8
// solution.recurse("-2^(-2)",0); // 0.25 3
// solution.recurse("-(-2^(-2))+2+(-(-2^(-2)))",0); // 1.5 10
// solution.recurse("(-2)*(-2)",0); // 4 3
// solution.recurse("(-2)/(-2)",0); // 1 3
// solution.recurse("sin(-30)",0); // -0.5 2
// solution.recurse("cos(-30)",0); // 0.87 2
// solution.recurse("tan(-30)",0); // -0.58 2
// solution.recurse("2+8*(9/4-1.5)^(1+1)",0); // 6.48 6
// solution.recurse("tan(44+sin(89-cos(180)^2))",0); // 1 6
// solution.recurse("-cos(180)^2",0); // -1 3
// solution.recurse("0+0.304",0); // 0.3 1
// solution.recurse("cos(3 + 19*3)", 0);
// solution.recurse("2*(589+((2454*0.1548/0.01*(-2+9^2))+((25*123.12+45877*25)+25))-547)", 0);
}
public String doOp(String op, String arg1, String arg2){
switch(op) {
case "^" : return String.valueOf(Math.pow(Double.parseDouble(arg1), Double.parseDouble(arg2)));
case "*" : return String.valueOf(Double.parseDouble(arg1) * Double.parseDouble(arg2));
case "/" : return String.valueOf(Double.parseDouble(arg1) / Double.parseDouble(arg2));
case "+" : return String.valueOf(Double.parseDouble(arg1) + Double.parseDouble(arg2));
case "-" : return String.valueOf(Double.parseDouble(arg1) - Double.parseDouble(arg2));
case "sin" : return String.valueOf(Math.sin(Double.parseDouble(arg1)/180*Math.PI));
case "cos" : return String.valueOf(Math.cos(Double.parseDouble(arg1)/180*Math.PI));
case "tan" : return String.valueOf(Math.tan(Double.parseDouble(arg1)/180*Math.PI));
default : throw new IllegalArgumentException();
}
}
public String doOp(String op, String arg1){
return doOp(op, arg1, null);
}
public boolean isDigit(char input){
return String.valueOf(input).matches("[0-9\\.]");
}
public boolean isOp(char input){
return String.valueOf(input).matches("[\\^\\*\\-\\+/]");
}
public boolean isFunc(char input){
return String.valueOf(input).matches("\\p{Alpha}");
}
public String getNumber(char[] input, int index){
String number = "";
char digit;
while (index < input.length && isDigit(digit = input[index])){
number += digit;
index++;
}
return number;
}
public String getFunc(char[] input, int index){
String func = "";
char letter;
while (index < input.length && isFunc(letter = input[index])){
func += letter;
index++;
}
return func;
}
public String getSub(Integer i, char[] expr){
int opened = 1;
int startIndex = ++i;
for (; i < expr.length; i++){
if (expr[i] == '(') opened++;
if (expr[i] == ')') opened--;
if (opened == 0) return String.valueOf(expr, startIndex, i - startIndex);
}
throw new IndexOutOfBoundsException();
}
public String getOperand(char[] expr, int i){
String operand = "";
if (isDigit(expr[i])){
operand += getNumber(expr, i);
} else if (isFunc(expr[i])){
String func = getFunc(expr, i);
i += func.length();
String arg = getSub(i, expr);
operand += func + "(" + arg + ")";
} else if (expr[i] == '('){
operand = "(" + getSub(i, expr) + ")";
}
return operand;
}
public int countOps(String expression){
String[] str = expression.split("sin|cos|tan|\\*|\\-|\\+|\\-|/|\\^");
return str.length;
}
public String recurse(final String expression, int countOperation) {
boolean topLevel = countOperation == 0;
List<String> operands = new ArrayList<String>();
List<String> operators = new ArrayList<String>();
char[] expr = expression.replace(" ", "").toCharArray();
int i = 0;
Double dbl;
try {
dbl = Double.parseDouble(expression);
if (!topLevel) return String.valueOf(dbl);
} catch (NumberFormatException e){
}
while (i < expr.length){
if (i < expr.length && i == 0 && expr[i] == '-'){
// i++;
// String sign = "";
// if (i < expr.length && expr[i] == '-') i++; // -- -> +
// else sign = "-";
// String operand = getOperand(expr, i);
// String pow = "";
// i += operand.length();
// if (i < expr.length && expr[i] == '^'){
// i++;
// pow = getOperand(expr, i);
// i += pow.length();
// operand = recurse(operand + "^" + pow, 1);
// } else
// operand = recurse(operand, 1);
// operands.add(!operand.equals("0")?sign + operand:"0");
operands.add("-1");
operators.add("*");
i++;
}
if (i < expr.length && isFunc(expr[i])) {
String func = getFunc(expr, i);
i += func.length();
String arg = getSub(i, expr);
i += arg.length() + 2;
operands.add(doOp(func.toLowerCase(), recurse(arg, 1)));
}
if (i < expr.length && isDigit(expr[i])){
String operand = getNumber(expr, i);
operands.add(operand);
i += operand.length();
}
if (i < expr.length && isOp(expr[i])){
operators.add(String.valueOf(expr[i++]));
}
if (i < expr.length && expr[i] == '('){
String operand = getSub(i, expr);
operands.add(recurse(operand, 1));
i += operand.length() + 2;
}
}
//
String[] operations = {"\\^", "\\*|/", "\\-|\\+"};
for (String match : operations) {
int opIndex = 0;
while (opIndex < operators.size()) {
String op = operators.get(opIndex);
if (op.matches(match)) {
String res = doOp(operators.get(opIndex),
recurse(operands.get(opIndex), 1),
recurse(operands.get(opIndex + 1), 1));
operators.remove(opIndex);
operands.remove(opIndex + 1);
operands.remove(opIndex);
operands.add(opIndex, res);
} else opIndex++;
}
}
String res = operands.get(0);
if (topLevel) {
countOperation = countOps(expression);
String formatted = new DecimalFormat("#.##").format(Double.parseDouble(res)).replace(",", ".");
if (Double.parseDouble(formatted) == 0) formatted = "0";
System.out.format("%s %d\n",
formatted,
countOperation - 1);
}
return res;
}
public Solution() {
//don't delete
}
}