문자열 계산기

문자열 계산기

자바로 만드는 문자열 계산기

 

📕 요구사항


  • 사용자가 입력한 문자열 값에 따라 사칙연산을 수행할 수 있는 계산기를 구현해야 한다.
  • 문자열 계산기는 사칙연산의 계산 우선순위가 아닌 입력 값에 따라 계산 순서가 결정된다. 즉, 수학에서는 곱셈, 나눗셈이 덧셈, 뺄셈 보다 먼저 계산해야 하지만 이를 무시한다.
  • 예를 들어 2 + 3 \* 4 / 2와 같은 문자열을 입력할 경우 2 + 3 \* 4 / 2 실행 결과인 10을 출력해야 한다.

 

public class StringCalculator {
    
    private String[] values;
    
    private LinkedList<Double> operands;
    private LinkedList<String> operators;
    
    private double result;
    
    public StringCalculator() {
        this(new LinkedList<>(), new LinkedList<>());
    }
    
    private StringCalculator(LinkedList<Double> operands, LinkedList<String> operators) {
        this.operands = operands;
        this.operators = operators;
    }
    
    public double getResult() {
        return result;
    }
    
    public void calculate() {
        result = operands.poll();
        while(operands.size() != 0) {
            Operator operator = Operator.of(operators.poll());
            result = operator.calculate(result, operands.poll());
        }
    }
    
    public void enter(final String s) {
        values = s.split(" ");
        if(values.length < 3) {
            throw new IllegalArgumentException("입력값이 올바르지 않습니다");
        }
        for(int i = 0; i < values.length; i++) {
            validate(i, values[i]);
            add(values[i]);
        }
    }
    
    private void validate(final int idx, final String value) {
        if(idx % 2 == 0 && !isNumeric(value)) {
            throw new IllegalArgumentException("입력값이 올바르지 않습니다");
        }
        if(idx % 2 == 1 && isNumeric(value)) {
            throw new IllegalArgumentException("입력값이 올바르지 않습니다");
        }
    }
    
    private void add(final String value) {
        if(isNumeric(value)) {
            operands.add(valueOf(value));
        }
        if(!isNumeric(value)) {
            operators.add(value);
        }
    }
    
    private static boolean isNumeric(final String s) {
        if("".equals(s)) {
            return false;
        }
        return s.matches("-?\\d+(\\.\\d+)?");
    }
    
    private enum Operator {
        PLUS("+", (e1, e2)->e1 + e2),
        MINUS("-", (e1, e2)->e1 - e2),
        DIVISION("/", (e1, e2)->e1 / e2),
        MULTI("*", (e1, e2)->e1 * e2);
        
        private String operator;
        private BinaryOperator<Double> operating;
        
        Operator(final String operator, final BinaryOperator<Double> operating) {
            this.operator = operator;
            this.operating = operating;
        }
        
        private static Operator of(final String operator) {
            return Arrays.stream(Operator.values())
                         .filter(value->value.operator.equals(operator))
                         .findFirst()
                         .orElseThrow(()->new IllegalArgumentException("유효한 연산자 형식이 아닙니다."));
        }
        
        private Double calculate(final Double e1, final Double e2) {
            return operating.apply(e1, e2);
        }
    }
    
}

 

class StringCalculatorTest {
    
    StringCalculator calculator;
    
    @BeforeEach
    void setUp() {
        calculator = new StringCalculator();
    }
    
    @DisplayName("입력_테스트")
    @ParameterizedTest
    @ValueSource(strings = {"",
                            "++*/",
                            "12345",
                            "2 3 42",
                            "2 + + * 4 / 2",
                            "+ + + + + + /,"})
    void enter(String param) {
        assertThatThrownBy(()->{
            calculator.enter(param);
        }).isInstanceOf(IllegalArgumentException.class)
          .hasMessageContaining("입력값이 올바르지 않습니다");
    }
    
    @DisplayName("계산_테스트")
    @ParameterizedTest
    @CsvSource(value = {"1 + 2:3",
                        "4 - 2:2",
                        "6 * 2:12",
                        "8 / 4:2",
                        "2 * 3 / 3 / 2:1",
                        "2 + 3 * 4 / 2:10"}, delimiter = ':')
    void calculate(String param, double expected) {
        calculator.enter(param);
        calculator.calculate();
        assertThat(calculator.getResult()).isEqualTo(expected);
    }
    
}

 


© 2022. All rights reserved.