# Evaluating an expression with integers, +, and *, as well as -, / - revision 3

The original question came from this web site.

Revision 1

Revision 2

And this is the third revision. I delete spaces and validate an equation before computing.

public class Main {

private static final String EQUATION_REGEX = "^-?\\d+((\\/|\\*|\\+|-)\\d+)*$"; // http://www.careercup.com/question?id=4911380140392448 public static void main(String[] args) { String equationWithAllSigns = "-1 * 5 * 4/2 - 8*9 - 16+1"; // Delete spaces equationWithAllSigns = equationWithAllSigns.replaceAll("\\s+", ""); // Compute the equation if it's valid if (equationWithAllSigns.matches(EQUATION_REGEX)) { double allSignsResult = computeWithAllOperations(equationWithAllSigns); System.out.println(allSignsResult); } else { System.out.println("Invalid equation"); } } private static double computeWithAllOperations(String input) { double result = 0.0; /* * 1. Replace - with +- except the minus which is the first symbol of * the input. * 2. Split the input string by + * 3. Calculate the products and quotients * 4. Sum up the results */ // (\\d)- is used instead of - to support strings starting with - String parts[] = input.replaceAll("(\\d)-", "$1+-").split("\\+");
for (String part : parts) {
result += computeMultAndDivision(part);
}
return result;
}

private static double computeMultAndDivision(String part) {
String[] parts = part.split("(?=[/*])|(?<=[/*])");
double result = Double.parseDouble(parts[0]);
for (int i = 1; i < parts.length; i += 2) {
String op = parts[i];
double val = Double.parseDouble(parts[i + 1]);
switch (op) {
case "*":
result *= val;
break;
case "/":
result /= val;
break;
}
}
return result;
}
}


I don't consider 2 * -3 a valid equation. It should look like this:

-2*3

What if you need to multiply two negative integers? :p Hold that thought for awhile...

# Validation logic

Even if we suppose you have made a case for your existing validation logic, it should belong to computeWithAllOperations(), possibly throwing an IllegalArgumentException exception containing a message to let the caller know what went wrong. You may want to go one step further to give a brief documentation about this on the method's Javadoc.

# Handling -

Your code transforms the - sign based on a preceding digit, which is a slightly odd twist in logic. Instead, I think you should be checking whether a - sign is preceded by any other mathematical operators ignoring whitespaces, which will yield the following change:

final String parts[] = input.replaceAll("\\s+", "")
.replaceAll("--", "+")
.replaceAll("((?<![/*+])-)", "+\$1");


Just like your original code, we strip out whitespaces, then transform a 'minus negative' operation into an addition, and finally replace only the - signs that do not follow other mathematical operators: /, * and +. These are the only cases when we need to treat it as a subtraction rather than to signify a negative value. More can be added here to support % and/or ^.

However, this change does introduce a slight quirk, which changes expressions starting with a negative integer to "+-1*5...". To mitigate that, we can do a simple short-circuiting in computeMultAndDivision():

private static final Pattern REGEX = Pattern.compile("(?=[/*%^])|(?<=[/*%^])");

public static double computeMultAndDivision(final String part) {
final String[] parts = REGEX.split(part);
if (parts[0].isEmpty()) {
return 0;
}
...
}


# Unit testing

Last but not least, I'll suggest doing proper unit testing for your utility method to assert its correctness. :)