Approximate Development Time: 4-6 hours
package com.vladimirlevin.calc; import junit.framework.TestCase; public class TestCalculator extends TestCase { public void testAdd() { Calculator calc = new Calculator(); String result = calc.eval("1 + 1"); assertEquals("2", result); } public void testAddWithNoWhitespace() { Calculator calc = new Calculator(); String result = calc.eval("1+1"); assertEquals("2", result); } public void testSubtract() { Calculator calc = new Calculator(); String result = calc.eval("5 - 2"); assertEquals("3", result); } public void testMultiply() { Calculator calc = new Calculator(); String result = calc.eval("16 * 2"); assertEquals("32", result); } public void testDivide() { Calculator calc = new Calculator(); String result = calc.eval("9 / 3"); assertEquals("3", result); } public void testSimpleExpression() { Calculator calc = new Calculator(); String result = calc.eval("9 + 3 - 7"); assertEquals("5", result); } public void testOperatorPrecedence() { Calculator calc = new Calculator(); String result = calc.eval("12 + 4 * 9"); assertEquals("48", result); } public void testOperatorPrecedenceLongerExpression() { Calculator calc = new Calculator(); String result = calc.eval("12 + 4 * 10 - 6 + 14 / 2"); assertEquals("53", result); } public void testParentheses() { Calculator calc = new Calculator(); String result = calc.eval("(10 + 2) / 6"); assertEquals("2", result); } public void testParenthesesLongerExpression() { Calculator calc = new Calculator(); String result = calc.eval("((10+2) * 2)/(6-1)"); assertEquals("4", result); } public void testParenthesesAroundExpression() { Calculator calc = new Calculator(); String result = calc.eval("(100 + 100)"); assertEquals("200", result); } } |
package com.vladimirlevin.calc; public class Calculator { public String eval(String expr) { return new ComplexExpression(expr).eval(); } } |
package com.vladimirlevin.calc; import java.util.List; import java.util.LinkedList; import java.util.StringTokenizer; abstract class Expression { protected List tokens = new LinkedList(); public Expression(String expr) { String delimiters = " ()\n\r\t" + Operator.operators(); StringTokenizer tokenizer = new StringTokenizer(expr, delimiters, true); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); if (!isWhitespace(token)) tokens.add(token); } } public Expression(List tokens) { this.tokens = tokens; } public abstract String eval(); protected void replace(int startIndex, int endIndex, String newValue) { tokens.add(startIndex, newValue); int itemsToRemove = endIndex - startIndex; for (int i=0; i<itemsToRemove; i++) tokens.remove(startIndex+1); } private boolean isWhitespace(String token) { return token.equals(" ") || token.equals("\n") || token.equals("\t"); } } |
package com.vladimirlevin.calc; import java.util.List; class SimpleExpression extends Expression { public SimpleExpression(String expr) { super(expr); } public SimpleExpression(List tokens) { super(tokens); } public String eval() { for (int i=0; i<Operator.operatorsByPrecence.length; i++) evaluateOperationsByPriority(Operator.operatorsByPrecence[i]); return (String) tokens.get(0); } private void evaluateOperationsByPriority(List operators) { for (int j=0; j<tokens.size(); j++) { String token = (String) tokens.get(j); if (operators.contains(token)) { String value = new Operator(token).calc( (String) tokens.get(j-1), (String) tokens.get(j+1)); replace(j-1, j+2, value); j--; } } } } |
package com.vladimirlevin.calc; import java.util.List; import java.util.LinkedList; class ComplexExpression extends Expression { public ComplexExpression(String expr) { super(expr); } public ComplexExpression(List tokens) { super(tokens); } public String eval() { while (tokens.size() > 1) evaluateInnermostExpression(); return (String) tokens.get(0); } private void evaluateInnermostExpression() { LinkedList found = new LinkedList(); int [] delims = findInnermostExpression(found); SimpleExpression innermostExpression = new SimpleExpression(found); replace(delims[0], delims[1], innermostExpression.eval()); } private int[] findInnermostExpression(List found) { int innerLeftParen = 0; for (int i=0; i<tokens.size(); i++) { if (tokens.get(i).equals("(")) innerLeftParen = i; if (tokens.get(i).equals(")")) { found.addAll(tokens.subList(innerLeftParen+1, i)); return new int[] {innerLeftParen, i+1}; } } found.addAll(tokens); return new int[] { 0, tokens.size() }; } } |
package com.vladimirlevin.calc; import java.util.ArrayList; class Operator { private static final ArrayList highPriorityOperators = new ArrayList(); private static final ArrayList lowPriorityOperators = new ArrayList(); public static final ArrayList[] operatorsByPrecence = { highPriorityOperators, lowPriorityOperators }; static { highPriorityOperators.add("*"); highPriorityOperators.add("/"); lowPriorityOperators.add("+"); lowPriorityOperators.add("-"); } private String operator; public Operator(String operator) { this.operator = operator; } public static String operators() { StringBuffer tokens = new StringBuffer(); for (int i=0; i<operatorsByPrecence.length; i++) for (int j=0; j<operatorsByPrecence[i].size(); j++) tokens.append(operatorsByPrecence[i].get(j)); return tokens.toString(); } public String calc (String leftVal, String rightVal) { int leftValue = Integer.parseInt(leftVal); int rightValue = Integer.parseInt(rightVal); if (operator.equals("+")) leftValue += rightValue; else if (operator.equals("-")) leftValue -= rightValue; else if (operator.equals("*")) leftValue *= rightValue; else if (operator.equals("/")) leftValue /= rightValue; return String.valueOf(leftValue); } } |