diff --git a/README.md b/README.md index 79ea6bfd9a..d2975eeea5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,30 @@ # java-calculator-precourse -![문제 원문1](calculator-description-1.png) -![문제 원문2](calculator-description-2.png) +## 구현 기능 목록 + +### 입력 문자열 처리 + +- 빈 문자열인 경우 + - [x] null 또는 빈 문자열("") 또는 1개 이상의 공백 입력 시 0을 반환 + +- 커스텀 구분자를 지정한 경우 + - [x] 커스텀 구분자가 `//`로 시작해 `\n`가 포함되는지 확인 + - [x] 입력 문자열에서 커스텀 구분자를 추출 + - 1개 이상의 구분자이며, 문자와 숫자 모두 가능하다. + - [x] 추출한 커스텀 구분자를 기본 구분자 목록에 추가 + - [x] 커스텀 구분자 지정 패턴(\n으로 끝나는 문자열) 이후의 문자열 추출 + +- 공통 + - [x] 구분자로 입력받은 문자열을 분리한다. + - 계산기에서 모든 예외를 처리 하므로 일단 구분자로 모든 문자열을 분리한다. + +### 계산기 + +- [x] 분리한 문자열을 양수 값으로 변환해 더해준다. +- [x] 양수 값 이외의 값이 배열에 들어있는 경우 예외 발생 +- [x] 합계가 정수 최댓값을 초과하는 경우 예외 발생 +- [x] 추출한 숫자의 합 반환 + +### 리펙토링 +- [x] CustomController 클래스를 내부클래스로 변경, static 메서드를 인스턴스 메서드로 변경 +- [x] 예외 발생 시 IllegalArgumentException(e)를 던져 stacktrace에 에러메시지 출력 +- [x] 변수 이름 변경 VALID_CUSTOM_INPUT -> CUSTOM_DELIMITER_PATTERN \ No newline at end of file diff --git a/src/main/java/calculator/Application.java b/src/main/java/calculator/Application.java index 573580fb40..eb227b4015 100644 --- a/src/main/java/calculator/Application.java +++ b/src/main/java/calculator/Application.java @@ -1,7 +1,15 @@ package calculator; +import camp.nextstep.edu.missionutils.Console; + public class Application { public static void main(String[] args) { // TODO: 프로그램 구현 + System.out.println("덧셈할 문자열을 입력헤주세요."); + String input = Console.readLine(); + + Calculator calculator = new Calculator(); + int result = calculator.calculate(input); + System.out.println("결과 : " + result); } -} +} \ No newline at end of file diff --git a/src/main/java/calculator/Calculator.java b/src/main/java/calculator/Calculator.java new file mode 100644 index 0000000000..445e4a61ed --- /dev/null +++ b/src/main/java/calculator/Calculator.java @@ -0,0 +1,73 @@ +package calculator; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Calculator { + private Delimiter delimiter; + private String[] numbers; + private int result; + + public int calculate(String input) { + if (input == null || input.isBlank()) { + return 0; + } + + CustomController customController = new CustomController(); + input = customController.getNewInputIfCustom(input); + + if (delimiter == null) { + delimiter = new Delimiter(); + } + + numbers = delimiter.split(input); + calculateResult(); + + return result; + } + + private void calculateResult() { + for (String number : numbers) { + // 만약 s가 숫자(양수)가 아니면 IllegalArgumentException 예외 발생 + // 오버플로우 발생 시 예외 발생 + try { + result = safeAdd(result, Integer.parseUnsignedInt(number)); + } catch (RuntimeException e) { + throw new IllegalArgumentException(e); + } + } + } + + private int safeAdd(int result, int number) { + if (result > Integer.MAX_VALUE - number) { + throw new ArithmeticException("Overflow"); + } + return result + number; + } + + private class CustomController { + private static final String CUSTOM_DELIMITER_PATTERN = "^//(.*)\\\\n(.*)"; + private static final int CUSTOM_DELIMITER_GROUP = 1; + private static final int CUSTOM_PURE_INPUT_GROUP = 2; + + private String getNewInputIfCustom(String input) { + Pattern pattern = Pattern.compile(CUSTOM_DELIMITER_PATTERN); + Matcher matcher = pattern.matcher(input); + + if (matcher.matches()) { + String customDelimiter = extractCustomDelimiter(matcher); + delimiter = new Delimiter(customDelimiter); + input = extractPureInput(matcher); + } + return input; + } + + private String extractCustomDelimiter(Matcher matcher) { + return matcher.group(CUSTOM_DELIMITER_GROUP); + } + + private String extractPureInput(Matcher matcher) { + return matcher.group(CUSTOM_PURE_INPUT_GROUP); + } + } +} \ No newline at end of file diff --git a/src/main/java/calculator/Delimiter.java b/src/main/java/calculator/Delimiter.java new file mode 100644 index 0000000000..f332b0c5a8 --- /dev/null +++ b/src/main/java/calculator/Delimiter.java @@ -0,0 +1,17 @@ +package calculator; + +public class Delimiter { + private final String delimiter; + + public Delimiter() { + delimiter = ",:"; + } + + public Delimiter(String customDelimiter) { + this.delimiter = ",:" + customDelimiter; + } + + public String[] split(String input) { + return input.split("[" + delimiter + "]"); + } +} \ No newline at end of file diff --git a/src/test/java/calculator/ApplicationTest.java b/src/test/java/calculator/ApplicationTest.java index 93771fb011..f49e6f674f 100644 --- a/src/test/java/calculator/ApplicationTest.java +++ b/src/test/java/calculator/ApplicationTest.java @@ -8,6 +8,14 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; class ApplicationTest extends NsTest { + @Test + void 기본_구분자_사용() { + assertSimpleTest(() -> { + run("1:2,3"); + assertThat(output()).contains("결과 : 6"); + }); + } + @Test void 커스텀_구분자_사용() { assertSimpleTest(() -> {