문자열 계산기
in Diary
자바로 만드는 문자열 계산기
📕 요구사항
- 사용자가 입력한 문자열 값에 따라 사칙연산을 수행할 수 있는 계산기를 구현해야 한다.
- 문자열 계산기는 사칙연산의 계산 우선순위가 아닌 입력 값에 따라 계산 순서가 결정된다. 즉, 수학에서는 곱셈, 나눗셈이 덧셈, 뺄셈 보다 먼저 계산해야 하지만 이를 무시한다.
- 예를 들어
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);
}
}