4
\$\begingroup\$

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;
    }
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

From your second revision:

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. :)

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.