Сразу скажу код получился объёмный. Все разделено на методы. Предусмотрены все смоделированные мною ситуации и коллизии. Также проходит абсолютно все тестовые примеры из комментов. Результат один в один. Прошу помочь
package com.javarush.task.task34.task3404;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
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
}
public void recurse(final String expression, int countOperation) {
if (expression.matches("(-|\\+)?\\d+\\.?\\d*")) {
String str = expression.replaceAll("\\s", "");
if (countOperation == 0) // если изначально пришло отрицательное число без операций
countOperation += minus(expression);
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(Locale.US);
DecimalFormat decimalFormat = new DecimalFormat("#.##", otherSymbols);
if (str.matches("-0.0")) // бывает и так
System.out.println(decimalFormat.format(Double.parseDouble("0")) + " " + countOperation);
else if (str.matches("\\+\\d+\\.?\\d*")) // если пришло число с знаком + перед ним
System.out.println(decimalFormat.format(Double.parseDouble(str.substring(1))) + " " + countOperation);
else
System.out.println(decimalFormat.format(Double.parseDouble(str)) + " " + countOperation);
}
else {
String str = expression.replaceAll("\\s", "");
if (countOperation == 0) // блок проверки на знак "-" в начале строки или после левой скобки (выполняется однократно)
countOperation +=minus(expression);
Pattern pattern1 = Pattern.compile("(\\()((-|\\+)?\\d+\\.?\\d*)(\\))");
Matcher matcher1 = pattern1.matcher(str);
String s;
if (matcher1.find()) { // блок раскрытия самых внутренних скобок
str = withoutParentheses(str);
str = artefacts(str);
}
if (str.matches("(-|\\+)?\\d+\\.?\\d*")) {
recurse(str, countOperation);
return; // для остановки рекурсии на текущей итерации, так как осталось голое число, которое необходимо вывести в виде готового результата
}
countOperation++;
//System.out.println("Выражение после того, как раскрыли скобки и убрали арты: " + str);
Pattern pattern2 = Pattern.compile("(-?\\d+\\.?\\d*)(\\^|/|\\*|-|\\+)(-?\\d+\\.?\\d*)");
Matcher matcher2 = pattern2.matcher(str);
if (matcher2.find()) {
String simple = simpleOps(str);
if (simple.equals(str))
countOperation--;
recurse(simple, countOperation);
}
else {
String trigonometric = trigonometricOps(str);
if (trigonometric.equals(str))
countOperation--;
recurse(trigonometricOps(str), countOperation);
}
}
}
public int minus(String s) {
Pattern pattern = Pattern.compile("(^|\\()-");
Matcher matcher = pattern.matcher(s);
int counter = 0;
while (matcher.find()) {
counter+=1;
}
return counter;
}
public String artefacts(String s) {
Pattern pattern1 = Pattern.compile("(\\+|-)(-)");
Matcher matcher1 = pattern1.matcher(s);
Pattern pattern2 = Pattern.compile("(\\+|-)(\\+)");
Matcher matcher2 = pattern2.matcher(s);
String art = null;
if (matcher1.find()) {
if (matcher1.group(1).equals("+")) {
art = s.replace(s.substring(matcher1.start(), matcher1.end()), "-");
}
else {
art = s.replace(s.substring(matcher1.start(), matcher1.end()), "+");
}
}
if (matcher2.find()) {
if (matcher2.group(1).equals("+")) {
art = s.replace(s.substring(matcher2.start(), matcher2.end()), "+");
}
else {
art = s.replace(s.substring(matcher2.start(), matcher2.end()), "-");
}
}
if (!(art == null))
return art;
return s;
}
public String withoutParentheses(String s) {
Pattern pattern = Pattern.compile("((sin|cos|tan)?)(\\()((-|\\+)?\\d+\\.?\\d*)(\\))");
Matcher matcher = pattern.matcher(s);
String without;
StringBuffer sb = new StringBuffer(s);
int count = 0;
while (matcher.find()) {
if (!((s.indexOf("^") == matcher.end() && matcher.group(4).startsWith("-")) || matcher.group(1).equals("sin")
|| matcher.group(1).equals("cos") || matcher.group(1).equals("tan"))) {
sb.delete(matcher.start() - count, matcher.start() + 1 - count);
count++;
sb.delete(matcher.end() - count - 1, matcher.end() - count);
count++;
}
}
without = sb.toString();
if (!without.equals(s))
return without;
return s;
}
public String simpleOps(String s) {
String[] arr = {"^", "/", "*", "-", "+"};
double d = 0;
for (String value : arr) {
String reg = String.format("(-?\\d+\\.?\\d*)(\\%s)(-?\\d+\\.?\\d*)", value);
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher(simpleString(s));
String resultReg = null;
while (matcher.find()) {
switch (matcher.group(2)) {
case "^": {
if (matcher.group(1).startsWith("-")) {
d = Math.pow(Double.parseDouble(matcher.group(1).substring(1)), Double.parseDouble(matcher.group(3)));
resultReg = matcher.group(1).substring(1) + "\\^" + matcher.group(3);
}
else {
d = Math.pow(Double.parseDouble(matcher.group(1)), Double.parseDouble(matcher.group(3)));
resultReg = matcher.group(1) + "\\^" + matcher.group(3);
}
break;
}
case "/": {
d = Double.parseDouble(matcher.group(1)) / Double.parseDouble(matcher.group(3));
resultReg = matcher.group(1) + "/" + matcher.group(3);
break;
}
case "*": {
d = Double.parseDouble(matcher.group(1)) * Double.parseDouble(matcher.group(3));
resultReg = matcher.group(1) + "\\*" + matcher.group(3);
break;
}
case "-": {
d = Double.parseDouble(matcher.group(1)) - Double.parseDouble(matcher.group(3));
resultReg = matcher.group(1) + "-" + matcher.group(3);
break;
}
case "+": {
d = Double.parseDouble(matcher.group(1)) + Double.parseDouble(matcher.group(3));
resultReg = matcher.group(1) + "\\+" + matcher.group(3);
break;
}
}
if (String.valueOf(d).length() > 6) {
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(Locale.US);
DecimalFormat decimalFormat = new DecimalFormat("#.##", otherSymbols);
return s.replaceFirst(resultReg, decimalFormat.format(new Double(d)));
}
return s.replaceFirst(resultReg, String.valueOf(d));
}
}
return s;
}
public String simpleString(String s) {
Pattern pattern1 = Pattern.compile("(\\()([^a-zA-Z\\(\\)]+)(\\))"); // самая внутренняя последовательность арифметических действий произвольной длины
Matcher matcher1 = pattern1.matcher(s);
Pattern pattern2 = Pattern.compile("[^a-zA-Z\\(\\)]+"); // последовательность арифметических действий произвольной длины
Matcher matcher2 = pattern2.matcher(s);
if (matcher1.find()) {
return matcher1.group(2);
}
else if (matcher2.find()) {
return matcher2.group();
}
return s;
}
public String trigonometricOps(String s) {
Pattern pattern1 = Pattern.compile("(sin|cos|tan)(\\()(-?\\d+\\.?\\d*)(\\))"); // тригонометрическая функция
Matcher matcher1 = pattern1.matcher(s);
Pattern pattern2 = Pattern.compile("(sin|cos|tan)(\\()(-?\\d+\\.?\\d*)(\\))(\\^)(.+)"); //тригонометрическая функция в степени
Matcher matcher2 = pattern2.matcher(s);
Pattern pattern3 = Pattern.compile("(\\()(-\\d+\\.?\\d*)(\\)\\^)(-?\\d+\\.?\\d*)"); // отрицательное число в степени
Matcher matcher3 = pattern3.matcher(s);
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(Locale.US);
DecimalFormat decimalFormat = new DecimalFormat("#.##", otherSymbols);
double d = 0;
double action;
double degrees;
if (matcher1.find()) {
action = Double.parseDouble(matcher1.group(3));
degrees = Math.toRadians(action);
switch (matcher1.group(1)) {
case "sin":
d = Math.sin(degrees);
break;
case "cos":
d = Math.cos(degrees);
break;
case "tan":
d = Math.tan(degrees);
break;
}
if (String.valueOf(d).length() > 6) {
String round = decimalFormat.format(new Double(d));
return s.replaceFirst("(sin|cos|tan)(\\()(-?\\d+\\.?\\d*)(\\))", round);
}
return s.replaceFirst("(sin|cos|tan)(\\()(-?\\d+\\.?\\d*)(\\))", String.valueOf(d));
}
else if (matcher2.find()) {
action = Double.parseDouble(matcher2.group(5));
degrees = Math.toRadians(action);
switch (matcher2.group(1)) {
case "sin":
d = Math.sin(degrees);
break;
case "cos":
d = Math.cos(degrees);
break;
case "tan":
d = Math.tan(degrees);
break;
}
if (String.valueOf(d).length() > 6) {
String round = decimalFormat.format(new Double(d)) + matcher2.group(5) + matcher2.group(6);
return s.replaceFirst("(sin|cos|tan)(\\()(-?\\d+\\.?\\d*)(\\))(\\^)(.+)", round);
}
return s.replaceFirst("(sin|cos|tan)(\\()(-?\\d+\\.?\\d*)(\\))(\\^)(.+)", String.valueOf(d));
}
else if (matcher3.find()) {
d = Math.pow(Double.parseDouble(matcher3.group(2)), Double.parseDouble(matcher3.group(4)));
if (String.valueOf(d).length() > 6) {
return s.replaceFirst("(\\()(-\\d+\\.?\\d*)(\\)\\^)(-?\\d+\\.?\\d*)", decimalFormat.format(new Double(d)));
}
return s.replaceFirst("(\\()(-\\d+\\.?\\d*)(\\)\\^)(-?\\d+\\.?\\d*)", String.valueOf(d));
}
return s;
}
public Solution () {
//don't delete
}
}