From 6a7e6ba3cd96659bbc038431b749047ff8334290 Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Sat, 18 Oct 2025 04:50:52 +0900 Subject: [PATCH 01/16] =?UTF-8?q?docs:=20README.md=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=ED=95=A0=20=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bd90ef0247..9ba71bb2c4 100644 --- a/README.md +++ b/README.md @@ -1 +1,73 @@ -# java-calculator-precourse \ No newline at end of file +## 1주차 미션 - 문자열 덧셈 계산기 +### 🔍 진행 방식 +- 미션은 **기능 요구사항** , **프로그래밍 요구사항**, **과제 진행 요구사항** 세가지로 구성되어 있다. +- 세 개의 요구 사항을 만족하기 위해 노력한다. 특히 기능을 구현하기 전에 기능 목록을 만들고, 기능 단위로 커밋 하는 방식으로 진행한다 +- 기능 요구 사항에 기재되지 않은 내용은 스스로 판단하여 구현한다. +- 매주 진행할 미션은 화요일 오후 3시부터 확인할 수 있으며, 다음 주 월요일까지 구현을 완료하여 제출해야 한다. 제출은 일요일 오후 3시부터 가능하다. + - 정해진 시간을 지키지 않을 경우 미션을 제출하지 않은 것으로 간주한다. + - 종료 일시 이후에는 추가 푸시를 허용하지 않는다 + +### 💡 미션 제출 방식 +- 미션 구현을 완료한 후 GitHub을 통해 제출해야 한다. + - GitHub을 활용한 제출 방법은 [프리코스 과제 제출](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 문서를 참고해 + 제출한다. +- GitHub에 미션을 제출한 후 [우아한테크코스 지원](https://apply.techcourse.co.kr) 사이트에 접속하여 프리코스 과제를 제출한다. + - 자세한 방법은 [제출 가이드](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse#제출-가이드) 참고 + - **Pull Request만 보내고 지원 플랫폼에서 과제를 제출하지 않으면 최종 제출하지 않은 것으로 처리되니 주의한다.** + +### 🚨 과제 제출 전 체크 리스트 + +- 기능 구현을 모두 정상적으로 했더라도 **요구 사항에 명시된 출력값 형식을 지키지 않을 경우 0점으로 처리**한다. +- 기능 구현을 완료한 뒤 아래 가이드에 따라 테스트를 실행했을 때 모든 테스트가 성공적으로 실행되는지 확인한다. +- **테스트가 실패할 경우 0점으로 처리**되므로, 반드시 확인 후 제출한다. + +### ✏️ 테스트 실행 가이드 +- 터미널에서 `java -version` 을 실행하여 Java 버전이 21인지 확인한다. Eclipse 또는 IntelliJ IDEA와 같은 IDE에서 Java 21로 실행되는지 확인한다. +- 터미널에서 Mac 또는 Linux 사용자의 경우 ` ./gradlew clean test ` 명령을 실행하여 모든 테스트가 아래와 같이 통과하는지 확인한다. +``` +BUILD SUCCESSFUL in 0s +``` + +### 🚀 기능 요구사항 +- 입력한 문자열에서 숫자를 추출하여 더하는 계산기를 구현한다 +- 쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환한다. + - (예) "" => 0, "1,2" => 3, "1,2,3" => 6, "1,2:3" => 6 +- 앞의 기본 구분자(쉼표, 콜론) 외에 커스텀 구분자를 지정할 수 있다. 커스텀 구분자는 문자열 앞부분의 "//"와 "\n" 사이에 위치하는 문자를 커스텀 구분자로 사용한다 + - (예) 예를 들어 "//;\n1;2;3"과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다 +- 사용자가 잘못된 값을 입력한 경우 `IllegalArgumentException` 을 발생시킨 후 애플리케이션은 종료 되어야 한다. + +### 🛠️ 구현 기능 목록 +- [ ] 사용자로부터 문자열을 입력받는다 + - 문자열이 구분자와 양수로 구성되어 있는지 확인한다 + - 숫자만 입력한 경우 해당 숫자를 반환한다 + - 빈 문자열을 입력한 경우 0을 반환한다 + - 문자열이 잘못된 값일 경우 예외를 발생 시킨 후 애플리케이션을 종료한다 + - 빈 공백을 입력한 경우 + - 양수가 아닌 문자를 입력한 경우 + - 구분자와 양수 사이에 공백을 입력한 경우 + - 커스텀 구분자의 형식에 맞지 않게 입력한 경우 +- [ ] 커스텀 구분자를 지정한다 + - 커스텀 구분자는 문자열 앞부분의 `//` 와 `\n` 사이에 위치하는 문자를 커스텀 구분자로 사용한다 + - (예) `//;\n1;2;3` 과 같이 값을 입력할 경우 커스텀 구분자는 `;` 이며 결과값은 6이 반환되어야 한다. + - 커스텀 구분자는 1글자 이상일 수 있다. + - (예) `//;.\n1;.2;.3 ` 일때 커스텀 구분자는 `;. ` +- 기본 구분자 `,` `;` +- [ ] 문자열을 구분자를 기준으로 분리한다 +- [ ] 구분자를 기준으로 분리한 각 숫자를 합친다 +- [ ] 각 숫자를 합한 결과를 출력한다. + +**실행 결과 예시** +``` +덧셈할 문자열을 입력해 주세요 +//;\n1;2;3 +결과 : 6 +``` + +### 🎯 프로그래밍 요구 사항 +- JDK 21 버전에서 실행 가능해야 한다. +- 프로그램 실행의 시작점은 Application의 `main()`이다. +- build.gradle 파일은 변경할 수 없으며, 제공된 라이브러리 이외의 외부 라이브러리는 사용하지 않는다. +- 프로그램 종료 시 System.exit()를 호출하지 않는다. +- 프로그래밍 요구 사항에서 달리 명시하지 않는 한 파일, 패키지 등의 이름을 바꾸거나 이동하지 않는다. +- 자바 코드 컨벤션을 지키면서 프로그래밍한다. +- 기본적으로 [Java Style Guide](https://github.com/woowacourse/woowacourse-docs/tree/main/styleguide/java)를 원칙으로 한다. \ No newline at end of file From b8f6aa934256472eae70fa16bc76b3283a13c82f Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Sat, 18 Oct 2025 09:21:03 +0900 Subject: [PATCH 02/16] =?UTF-8?q?docs:=20README.md=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=ED=95=A0=20=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9ba71bb2c4..ac81979d72 100644 --- a/README.md +++ b/README.md @@ -38,22 +38,16 @@ BUILD SUCCESSFUL in 0s ### 🛠️ 구현 기능 목록 - [ ] 사용자로부터 문자열을 입력받는다 - - 문자열이 구분자와 양수로 구성되어 있는지 확인한다 - - 숫자만 입력한 경우 해당 숫자를 반환한다 - - 빈 문자열을 입력한 경우 0을 반환한다 - - 문자열이 잘못된 값일 경우 예외를 발생 시킨 후 애플리케이션을 종료한다 - - 빈 공백을 입력한 경우 - - 양수가 아닌 문자를 입력한 경우 - - 구분자와 양수 사이에 공백을 입력한 경우 - - 커스텀 구분자의 형식에 맞지 않게 입력한 경우 + - 문자열이 구분자와 양수로 구성되어 있는지 확인한다. + - 문자열이 잘못된 값일 경우 예외를 발생 시킨 후 애플리케이션을 종료한다. - [ ] 커스텀 구분자를 지정한다 - - 커스텀 구분자는 문자열 앞부분의 `//` 와 `\n` 사이에 위치하는 문자를 커스텀 구분자로 사용한다 + - 커스텀 구분자는 문자열 앞부분의 `//` 와 `\n` 사이에 위치하는 문자를 커스텀 구분자로 사용한다. - (예) `//;\n1;2;3` 과 같이 값을 입력할 경우 커스텀 구분자는 `;` 이며 결과값은 6이 반환되어야 한다. - 커스텀 구분자는 1글자 이상일 수 있다. - (예) `//;.\n1;.2;.3 ` 일때 커스텀 구분자는 `;. ` - 기본 구분자 `,` `;` -- [ ] 문자열을 구분자를 기준으로 분리한다 -- [ ] 구분자를 기준으로 분리한 각 숫자를 합친다 +- [ ] 문자열을 구분자를 기준으로 분리한다. +- [ ] 구분자를 기준으로 분리한 각 숫자를 합친다. - [ ] 각 숫자를 합한 결과를 출력한다. **실행 결과 예시** @@ -70,4 +64,8 @@ BUILD SUCCESSFUL in 0s - 프로그램 종료 시 System.exit()를 호출하지 않는다. - 프로그래밍 요구 사항에서 달리 명시하지 않는 한 파일, 패키지 등의 이름을 바꾸거나 이동하지 않는다. - 자바 코드 컨벤션을 지키면서 프로그래밍한다. -- 기본적으로 [Java Style Guide](https://github.com/woowacourse/woowacourse-docs/tree/main/styleguide/java)를 원칙으로 한다. \ No newline at end of file +- 기본적으로 [Java Style Guide](https://github.com/woowacourse/woowacourse-docs/tree/main/styleguide/java)를 원칙으로 한다. + +### 📚 라이브러리 +- `camp.nextstep.edu.missionutils `에서 제공하는 Console API를 사용하여 구현해야 한다. + - 사용자가 입력하는 값은 camp.nextstep.edu.missionutils.Console의 readLine()을 활용한다 \ No newline at end of file From 4ea1128c6f70f277169695ee3806f583ae070207 Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Sat, 18 Oct 2025 19:30:36 +0900 Subject: [PATCH 03/16] =?UTF-8?q?feat:=20=EB=AC=B8=EC=9E=90=EC=97=B4=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/calculator/Application.java | 4 ++++ .../calculator/controller/CalculatorController.java | 11 +++++++++++ src/main/java/calculator/message/Message.java | 8 ++++++++ src/main/java/calculator/view/Input.java | 11 +++++++++++ 4 files changed, 34 insertions(+) create mode 100644 src/main/java/calculator/controller/CalculatorController.java create mode 100644 src/main/java/calculator/message/Message.java create mode 100644 src/main/java/calculator/view/Input.java diff --git a/src/main/java/calculator/Application.java b/src/main/java/calculator/Application.java index 573580fb40..8191ea11d5 100644 --- a/src/main/java/calculator/Application.java +++ b/src/main/java/calculator/Application.java @@ -1,7 +1,11 @@ package calculator; +import calculator.controller.CalculatorController; + public class Application { public static void main(String[] args) { // TODO: 프로그램 구현 + CalculatorController calculatorController = new CalculatorController(); + calculatorController.run(); } } diff --git a/src/main/java/calculator/controller/CalculatorController.java b/src/main/java/calculator/controller/CalculatorController.java new file mode 100644 index 0000000000..65a3597baa --- /dev/null +++ b/src/main/java/calculator/controller/CalculatorController.java @@ -0,0 +1,11 @@ +package calculator.controller; + +import calculator.view.Input; + +public class CalculatorController { + public void run(){ + Input input = new Input(); + String value = input.readInput(); + + } +} diff --git a/src/main/java/calculator/message/Message.java b/src/main/java/calculator/message/Message.java new file mode 100644 index 0000000000..9ad2848c67 --- /dev/null +++ b/src/main/java/calculator/message/Message.java @@ -0,0 +1,8 @@ +package calculator.message; + +public abstract class Message { + + //입출력 관련 + public final static String INPUT_MESSAGE = "덧셈할 문자열을 입력해 주세요"; + +} diff --git a/src/main/java/calculator/view/Input.java b/src/main/java/calculator/view/Input.java new file mode 100644 index 0000000000..272de80477 --- /dev/null +++ b/src/main/java/calculator/view/Input.java @@ -0,0 +1,11 @@ +package calculator.view; + +import calculator.message.Message; +import camp.nextstep.edu.missionutils.Console; + +public class Input { + public String readInput() { + System.out.println(Message.INPUT_MESSAGE); + return Console.readLine(); + } +} From 31bfeaa4b23fd61fcaf4cc7fe78c3f1fd8490f27 Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Sat, 18 Oct 2025 22:06:21 +0900 Subject: [PATCH 04/16] =?UTF-8?q?feat:=20=EB=AC=B8=EC=9E=90=EC=97=B4=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EC=8B=9C=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/calculator/Application.java | 1 - .../java/calculator/domain/Calculator.java | 4 ++++ .../java/calculator/message/ErrorMessage.java | 8 ++++++++ .../{Message.java => SuccessMessage.java} | 2 +- src/main/java/calculator/view/Input.java | 18 +++++++++++++++--- 5 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 src/main/java/calculator/domain/Calculator.java create mode 100644 src/main/java/calculator/message/ErrorMessage.java rename src/main/java/calculator/message/{Message.java => SuccessMessage.java} (78%) diff --git a/src/main/java/calculator/Application.java b/src/main/java/calculator/Application.java index 8191ea11d5..bdd2b5b2cb 100644 --- a/src/main/java/calculator/Application.java +++ b/src/main/java/calculator/Application.java @@ -4,7 +4,6 @@ public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 CalculatorController calculatorController = new CalculatorController(); calculatorController.run(); } diff --git a/src/main/java/calculator/domain/Calculator.java b/src/main/java/calculator/domain/Calculator.java new file mode 100644 index 0000000000..1849f22927 --- /dev/null +++ b/src/main/java/calculator/domain/Calculator.java @@ -0,0 +1,4 @@ +package calculator.domain; + +public class Calculator { +} diff --git a/src/main/java/calculator/message/ErrorMessage.java b/src/main/java/calculator/message/ErrorMessage.java new file mode 100644 index 0000000000..fe97999593 --- /dev/null +++ b/src/main/java/calculator/message/ErrorMessage.java @@ -0,0 +1,8 @@ +package calculator.message; + +public abstract class ErrorMessage { + + //입출력 관련 + public final static String TRIM_ERROR = "문자열에 공백이 포함될 수 없습니다"; + +} diff --git a/src/main/java/calculator/message/Message.java b/src/main/java/calculator/message/SuccessMessage.java similarity index 78% rename from src/main/java/calculator/message/Message.java rename to src/main/java/calculator/message/SuccessMessage.java index 9ad2848c67..10e8af5fc8 100644 --- a/src/main/java/calculator/message/Message.java +++ b/src/main/java/calculator/message/SuccessMessage.java @@ -1,6 +1,6 @@ package calculator.message; -public abstract class Message { +public abstract class SuccessMessage { //입출력 관련 public final static String INPUT_MESSAGE = "덧셈할 문자열을 입력해 주세요"; diff --git a/src/main/java/calculator/view/Input.java b/src/main/java/calculator/view/Input.java index 272de80477..5eb9c4199b 100644 --- a/src/main/java/calculator/view/Input.java +++ b/src/main/java/calculator/view/Input.java @@ -1,11 +1,23 @@ package calculator.view; -import calculator.message.Message; +import calculator.message.ErrorMessage; +import calculator.message.SuccessMessage; import camp.nextstep.edu.missionutils.Console; public class Input { public String readInput() { - System.out.println(Message.INPUT_MESSAGE); - return Console.readLine(); + System.out.println(SuccessMessage.INPUT_MESSAGE); + String input = Console.readLine(); + + //입력값이 null인 경우 0을 반환 + if (input == null || input.isEmpty()) { + return "0"; + } + //공백만 입력하거나 공백을 문자에 포함한 경우의 예외 처리 + if (input.trim().isEmpty() || input.contains(" ") ) { + throw new IllegalArgumentException(ErrorMessage.TRIM_ERROR); + } + + return input; } } From b7fd63b2f15b0a1babbf0e77b2502d7b346b48e4 Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Sat, 18 Oct 2025 22:07:26 +0900 Subject: [PATCH 05/16] =?UTF-8?q?test:=20=EB=AC=B8=EC=9E=90=EC=97=B4=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/calculator/InputTest.java | 86 +++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/test/java/calculator/InputTest.java diff --git a/src/test/java/calculator/InputTest.java b/src/test/java/calculator/InputTest.java new file mode 100644 index 0000000000..687925ef44 --- /dev/null +++ b/src/test/java/calculator/InputTest.java @@ -0,0 +1,86 @@ +package calculator; + + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import calculator.message.ErrorMessage; +import calculator.view.Input; + +class InputTest { + + private final PrintStream originalOut = System.out; + private final InputStream originalInput = System.in; + private ByteArrayOutputStream outContent; + + private Input inputView; + + @BeforeEach + void setUp() { + inputView = new Input(); + outContent = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outContent)); + } + + @AfterEach + void tearDown() { + System.setOut(originalOut); + System.setIn(originalInput); + } + + @Test + @DisplayName("정상 입력하는 경우") + void testInput_success() { + String dummy = "//;\\n1;2;3"; + System.setIn(new ByteArrayInputStream(dummy.getBytes())); + + String result = inputView.readInput(); + + assertEquals("//;\\n1;2;3", result); + } + + @Test + @DisplayName("값을 입력하지 않은 경우 0을 반환한다") + void null_input() { + String dummy = "\n"; //아무것도 입력하지않고 Enter 친 경우 + System.setIn(new ByteArrayInputStream(dummy.getBytes())); + + String result = inputView.readInput(); + + assertEquals("0", result); + } + + @Test + @DisplayName("문자열에 공백이 포함될 경우 예외가 발생한다") + void include_spaces() { + String dummy = "// 1 ; 2 "; + System.setIn(new ByteArrayInputStream(dummy.getBytes())); + + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, + () -> inputView.readInput() + ); + assertEquals(ErrorMessage.TRIM_ERROR, exception.getMessage()); + } + + @Test + @DisplayName("문자열에 공백만 입력한 경우 예외가 발생한다") + void only_include_spaces() { + String dummy = " "; + System.setIn(new ByteArrayInputStream(dummy.getBytes())); + + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, + () -> inputView.readInput() + ); + assertEquals(ErrorMessage.TRIM_ERROR, exception.getMessage()); + } + +} From cd9efd17cbe9c063d9103f97d14c34a51a48e8ae Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Mon, 20 Oct 2025 09:06:52 +0900 Subject: [PATCH 06/16] =?UTF-8?q?feat:=20=EB=AC=B8=EC=9E=90=EC=97=B4=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=EC=9D=84=20=EB=B6=84=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EC=97=AC=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=ED=99=98=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CalculatorController.java | 11 ++++ .../java/calculator/domain/Separator.java | 59 +++++++++++++++++++ .../java/calculator/message/ErrorMessage.java | 6 ++ 3 files changed, 76 insertions(+) create mode 100644 src/main/java/calculator/domain/Separator.java diff --git a/src/main/java/calculator/controller/CalculatorController.java b/src/main/java/calculator/controller/CalculatorController.java index 65a3597baa..1dd33ac461 100644 --- a/src/main/java/calculator/controller/CalculatorController.java +++ b/src/main/java/calculator/controller/CalculatorController.java @@ -1,5 +1,8 @@ package calculator.controller; +import java.util.List; + +import calculator.domain.Separator; import calculator.view.Input; public class CalculatorController { @@ -7,5 +10,13 @@ public void run(){ Input input = new Input(); String value = input.readInput(); + //Separator + Separator separator = new Separator(value); + List numbers = separator.getNumbers(); + System.out.println("numbers = " + numbers); + + + + } } diff --git a/src/main/java/calculator/domain/Separator.java b/src/main/java/calculator/domain/Separator.java new file mode 100644 index 0000000000..d1452ea8b9 --- /dev/null +++ b/src/main/java/calculator/domain/Separator.java @@ -0,0 +1,59 @@ +package calculator.domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import calculator.message.ErrorMessage; + +public class Separator { + + private final List numbers; + + public Separator(String value) { + this.numbers = split(value); + } + //입력받은 문자열을 숫자 리스트로 변환 + public List split(String value){ + + String delimiter = "[,\n]"; //초기 구분자 설정 , \n + + String numbersPart = value; + //커스텀 구분자 확인 + if (value.startsWith("//")) { + int delimiterEndIndex = value.indexOf("\n"); + if (delimiterEndIndex == -1){ + throw new IllegalArgumentException(ErrorMessage.FORMAT_INCORRECT); + } + //사용자가 사용한 구분자 꺼내옴 + String customDelimiter = value.substring(2, delimiterEndIndex); + if (customDelimiter.isEmpty()) { + throw new IllegalArgumentException(ErrorMessage.DELIMITER_MISSING); + } + delimiter = Pattern.quote(value.substring(2,delimiterEndIndex)); + numbersPart = value.substring(delimiterEndIndex+1); + } + //구분자를 기준으로 숫자 문자열을 나눠 배열로 저장 + String[] tokens = numbersPart.split(delimiter); + + List result = new ArrayList<>(); + for (String token: tokens) { + if (!token.isEmpty()){ + try{ + //String -> Int + int num = Integer.parseInt(token); + //음수인지 확인 + if (num < 0) { + throw new IllegalArgumentException(ErrorMessage.NEGATIVE_NUMBER_NOT_ALLOWED); + } + }catch(NumberFormatException e){ + throw new IllegalArgumentException(ErrorMessage.ENTERED_NON_NUMERIC_VALUE); + } + } + } + return result; + } + public List getNumbers() { + return numbers; + } +} diff --git a/src/main/java/calculator/message/ErrorMessage.java b/src/main/java/calculator/message/ErrorMessage.java index fe97999593..809f0c0877 100644 --- a/src/main/java/calculator/message/ErrorMessage.java +++ b/src/main/java/calculator/message/ErrorMessage.java @@ -4,5 +4,11 @@ public abstract class ErrorMessage { //입출력 관련 public final static String TRIM_ERROR = "문자열에 공백이 포함될 수 없습니다"; + public final static String FORMAT_INCORRECT = "입력 형식이 잘못되었습니다"; + //구분자 , 입력값 검증 관련 + public final static String ENTERED_NON_NUMERIC_VALUE = "숫자가 아닌 값이 포함되어 있습니다"; + public final static String NEGATIVE_NUMBER_NOT_ALLOWED = "음수는 입력할 수 없습니다"; + public final static String DELIMITER_MISSING = "커스텀 구분자는 한자리 이상 포함되어 있어야 합니다"; + } From 8990b2bb38cb2d4df9a4346519784b2a5b38e2a8 Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Mon, 20 Oct 2025 09:15:26 +0900 Subject: [PATCH 07/16] =?UTF-8?q?feat:=20=EB=8D=A7=EC=85=88=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EB=B0=98=ED=99=98=ED=95=98=EB=8A=94=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CalculatorController.java | 6 ++++-- .../java/calculator/message/SuccessMessage.java | 2 ++ src/main/java/calculator/view/Output.java | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 src/main/java/calculator/view/Output.java diff --git a/src/main/java/calculator/controller/CalculatorController.java b/src/main/java/calculator/controller/CalculatorController.java index 1dd33ac461..94a7897276 100644 --- a/src/main/java/calculator/controller/CalculatorController.java +++ b/src/main/java/calculator/controller/CalculatorController.java @@ -4,6 +4,7 @@ import calculator.domain.Separator; import calculator.view.Input; +import calculator.view.Output; public class CalculatorController { public void run(){ @@ -13,9 +14,10 @@ public void run(){ //Separator Separator separator = new Separator(value); List numbers = separator.getNumbers(); - System.out.println("numbers = " + numbers); - + //print + Output output = new Output(); + output.output(numbers); } diff --git a/src/main/java/calculator/message/SuccessMessage.java b/src/main/java/calculator/message/SuccessMessage.java index 10e8af5fc8..cb3be04c92 100644 --- a/src/main/java/calculator/message/SuccessMessage.java +++ b/src/main/java/calculator/message/SuccessMessage.java @@ -2,7 +2,9 @@ public abstract class SuccessMessage { + //입출력 관련 public final static String INPUT_MESSAGE = "덧셈할 문자열을 입력해 주세요"; + public final static String OUTPUT_MESSAGE = "결과 :"; } diff --git a/src/main/java/calculator/view/Output.java b/src/main/java/calculator/view/Output.java new file mode 100644 index 0000000000..5abbdba1ad --- /dev/null +++ b/src/main/java/calculator/view/Output.java @@ -0,0 +1,15 @@ +package calculator.view; + +import java.util.List; + +import calculator.message.SuccessMessage; + +public class Output { + public void output(List numbers) { + int sum = 0; + for (Integer number : numbers) { + sum += number; + } + System.out.println(SuccessMessage.OUTPUT_MESSAGE + sum); + } +} From dc226b917b8bfccc2b936aa271e446f60d4d8a89 Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Mon, 20 Oct 2025 12:48:26 +0900 Subject: [PATCH 08/16] =?UTF-8?q?refactor:=20=EB=AC=B8=EC=9E=90=EC=97=B4?= =?UTF-8?q?=20=EC=9E=85=EB=A0=A5=EC=9D=84=20=EB=B6=84=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EC=97=AC=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=ED=99=98=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/calculator/domain/Calculator.java | 4 -- .../java/calculator/domain/Separator.java | 40 +++++++++---------- src/main/java/calculator/view/Output.java | 4 +- 3 files changed, 21 insertions(+), 27 deletions(-) delete mode 100644 src/main/java/calculator/domain/Calculator.java diff --git a/src/main/java/calculator/domain/Calculator.java b/src/main/java/calculator/domain/Calculator.java deleted file mode 100644 index 1849f22927..0000000000 --- a/src/main/java/calculator/domain/Calculator.java +++ /dev/null @@ -1,4 +0,0 @@ -package calculator.domain; - -public class Calculator { -} diff --git a/src/main/java/calculator/domain/Separator.java b/src/main/java/calculator/domain/Separator.java index d1452ea8b9..682c9e5cff 100644 --- a/src/main/java/calculator/domain/Separator.java +++ b/src/main/java/calculator/domain/Separator.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; import java.util.regex.Pattern; import calculator.message.ErrorMessage; @@ -13,46 +14,43 @@ public class Separator { public Separator(String value) { this.numbers = split(value); } - //입력받은 문자열을 숫자 리스트로 변환 - public List split(String value){ - - String delimiter = "[,\n]"; //초기 구분자 설정 , \n + public List split(String value) { + String delimiter = "[,\n]"; // 기본 구분자 ,와 개행 String numbersPart = value; - //커스텀 구분자 확인 - if (value.startsWith("//")) { - int delimiterEndIndex = value.indexOf("\n"); - if (delimiterEndIndex == -1){ - throw new IllegalArgumentException(ErrorMessage.FORMAT_INCORRECT); - } - //사용자가 사용한 구분자 꺼내옴 - String customDelimiter = value.substring(2, delimiterEndIndex); + + // 커스텀 구분자 처리 + Pattern pattern = Pattern.compile("//(.*)\\\\n(.*)", Pattern.DOTALL); + Matcher matcher = pattern.matcher(value); + + if (matcher.matches()) { + String customDelimiter = matcher.group(1); if (customDelimiter.isEmpty()) { throw new IllegalArgumentException(ErrorMessage.DELIMITER_MISSING); } - delimiter = Pattern.quote(value.substring(2,delimiterEndIndex)); - numbersPart = value.substring(delimiterEndIndex+1); + delimiter = Pattern.quote(customDelimiter); + numbersPart = matcher.group(2); // \n 뒤 숫자 문자열 } - //구분자를 기준으로 숫자 문자열을 나눠 배열로 저장 + String[] tokens = numbersPart.split(delimiter); List result = new ArrayList<>(); - for (String token: tokens) { - if (!token.isEmpty()){ - try{ - //String -> Int + for (String token : tokens) { + if (!token.isEmpty()) { + try { int num = Integer.parseInt(token); - //음수인지 확인 if (num < 0) { throw new IllegalArgumentException(ErrorMessage.NEGATIVE_NUMBER_NOT_ALLOWED); } - }catch(NumberFormatException e){ + result.add(num); + } catch (NumberFormatException e) { throw new IllegalArgumentException(ErrorMessage.ENTERED_NON_NUMERIC_VALUE); } } } return result; } + public List getNumbers() { return numbers; } diff --git a/src/main/java/calculator/view/Output.java b/src/main/java/calculator/view/Output.java index 5abbdba1ad..1e8c339da7 100644 --- a/src/main/java/calculator/view/Output.java +++ b/src/main/java/calculator/view/Output.java @@ -10,6 +10,6 @@ public void output(List numbers) { for (Integer number : numbers) { sum += number; } - System.out.println(SuccessMessage.OUTPUT_MESSAGE + sum); - } + System.out.println(SuccessMessage.OUTPUT_MESSAGE + " " + sum); } } + From 5fbdeae94db482eac0a051f25125d359b2ffebde Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Mon, 20 Oct 2025 15:08:42 +0900 Subject: [PATCH 09/16] =?UTF-8?q?refactor:=20=EC=88=AB=EC=9E=90=20?= =?UTF-8?q?=ED=8C=8C=EC=8B=B1=20=EB=B0=8F=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=9D=84=20Separator=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/calculator/domain/Separator.java | 46 +++++-------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/src/main/java/calculator/domain/Separator.java b/src/main/java/calculator/domain/Separator.java index 682c9e5cff..2cd9dfaba4 100644 --- a/src/main/java/calculator/domain/Separator.java +++ b/src/main/java/calculator/domain/Separator.java @@ -2,56 +2,34 @@ import java.util.ArrayList; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import calculator.message.ErrorMessage; public class Separator { + private final Delimiter delimiter; private final List numbers; public Separator(String value) { - this.numbers = split(value); + this.delimiter = Delimiter.of(value); + this.numbers = parseNumbers(delimiter.extractNumbers(value)); } - public List split(String value) { - String delimiter = "[,\n]"; // 기본 구분자 ,와 개행 - String numbersPart = value; - - // 커스텀 구분자 처리 - Pattern pattern = Pattern.compile("//(.*)\\\\n(.*)", Pattern.DOTALL); - Matcher matcher = pattern.matcher(value); - - if (matcher.matches()) { - String customDelimiter = matcher.group(1); - if (customDelimiter.isEmpty()) { - throw new IllegalArgumentException(ErrorMessage.DELIMITER_MISSING); - } - delimiter = Pattern.quote(customDelimiter); - numbersPart = matcher.group(2); // \n 뒤 숫자 문자열 - } - - String[] tokens = numbersPart.split(delimiter); - + private List parseNumbers(String nums) { List result = new ArrayList<>(); - for (String token : tokens) { - if (!token.isEmpty()) { - try { - int num = Integer.parseInt(token); - if (num < 0) { - throw new IllegalArgumentException(ErrorMessage.NEGATIVE_NUMBER_NOT_ALLOWED); - } - result.add(num); - } catch (NumberFormatException e) { - throw new IllegalArgumentException(ErrorMessage.ENTERED_NON_NUMERIC_VALUE); + for (String token: nums.split(delimiter.getRegex())){ + if(!token.isEmpty()) { + int num = Integer.parseInt(token); + //음수인경우 예외처리 + if (num < 0) { + throw new IllegalArgumentException(ErrorMessage.NEGATIVE_NUMBER_NOT_ALLOWED); } + result.add(num); } } return result; } - - public List getNumbers() { + public List getNumbers(){ return numbers; } } From 51a252c30ef88a3e48dd816722b9b7e8375e965c Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Mon, 20 Oct 2025 15:09:29 +0900 Subject: [PATCH 10/16] =?UTF-8?q?refactor:=20=EC=BB=A4=EC=8A=A4=ED=85=80?= =?UTF-8?q?=20=EA=B5=AC=EB=B6=84=EC=9E=90=20=EC=B2=98=EB=A6=AC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=9D=84=20Delimiter=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/calculator/domain/Delimiter.java | 34 ++++++++ src/test/java/calculator/InputTest.java | 86 ------------------- 2 files changed, 34 insertions(+), 86 deletions(-) create mode 100644 src/main/java/calculator/domain/Delimiter.java delete mode 100644 src/test/java/calculator/InputTest.java diff --git a/src/main/java/calculator/domain/Delimiter.java b/src/main/java/calculator/domain/Delimiter.java new file mode 100644 index 0000000000..2126e412bf --- /dev/null +++ b/src/main/java/calculator/domain/Delimiter.java @@ -0,0 +1,34 @@ +package calculator.domain; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import calculator.message.ErrorMessage; + +public class Delimiter { + private final String regex; + private final String pattern = "//(.*)\\\\n(.*)"; + + private Delimiter (String regax) { + this.regex = regax; + } + public static Delimiter of(String value) { + Pattern p = Pattern.compile("//(.*)\\\\\\\\n(.*)",Pattern.DOTALL); + Matcher m = p.matcher(value); + if (m.matches()) { + String custom = m.group(1); + if(custom.isEmpty()) { //커스텀 구분자가 빈 문자열이면 예외처리 + throw new IllegalArgumentException(ErrorMessage.DELIMITER_MISSING); + } + return new Delimiter(Pattern.quote(custom)); + } + return new Delimiter("[,\n]"); + } + public String extractNumbers(String value) { + Matcher m = Pattern.compile(pattern, Pattern.DOTALL).matcher(value); + return m.matches() ? m.group(2) : value; + } + public String getRegex() { + return regex; + } +} diff --git a/src/test/java/calculator/InputTest.java b/src/test/java/calculator/InputTest.java deleted file mode 100644 index 687925ef44..0000000000 --- a/src/test/java/calculator/InputTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package calculator; - - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.PrintStream; -import static org.junit.jupiter.api.Assertions.*; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import calculator.message.ErrorMessage; -import calculator.view.Input; - -class InputTest { - - private final PrintStream originalOut = System.out; - private final InputStream originalInput = System.in; - private ByteArrayOutputStream outContent; - - private Input inputView; - - @BeforeEach - void setUp() { - inputView = new Input(); - outContent = new ByteArrayOutputStream(); - System.setOut(new PrintStream(outContent)); - } - - @AfterEach - void tearDown() { - System.setOut(originalOut); - System.setIn(originalInput); - } - - @Test - @DisplayName("정상 입력하는 경우") - void testInput_success() { - String dummy = "//;\\n1;2;3"; - System.setIn(new ByteArrayInputStream(dummy.getBytes())); - - String result = inputView.readInput(); - - assertEquals("//;\\n1;2;3", result); - } - - @Test - @DisplayName("값을 입력하지 않은 경우 0을 반환한다") - void null_input() { - String dummy = "\n"; //아무것도 입력하지않고 Enter 친 경우 - System.setIn(new ByteArrayInputStream(dummy.getBytes())); - - String result = inputView.readInput(); - - assertEquals("0", result); - } - - @Test - @DisplayName("문자열에 공백이 포함될 경우 예외가 발생한다") - void include_spaces() { - String dummy = "// 1 ; 2 "; - System.setIn(new ByteArrayInputStream(dummy.getBytes())); - - IllegalArgumentException exception = assertThrows( - IllegalArgumentException.class, - () -> inputView.readInput() - ); - assertEquals(ErrorMessage.TRIM_ERROR, exception.getMessage()); - } - - @Test - @DisplayName("문자열에 공백만 입력한 경우 예외가 발생한다") - void only_include_spaces() { - String dummy = " "; - System.setIn(new ByteArrayInputStream(dummy.getBytes())); - - IllegalArgumentException exception = assertThrows( - IllegalArgumentException.class, - () -> inputView.readInput() - ); - assertEquals(ErrorMessage.TRIM_ERROR, exception.getMessage()); - } - -} From b6bb97416878350d2a7ac9ee1638a5e54e626af3 Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:03:44 +0900 Subject: [PATCH 11/16] =?UTF-8?q?fix:=20=EC=98=88=EC=99=B8=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/calculator/domain/Delimiter.java | 19 ++++++++++--------- .../java/calculator/domain/Separator.java | 11 ++++++++--- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/main/java/calculator/domain/Delimiter.java b/src/main/java/calculator/domain/Delimiter.java index 2126e412bf..b462c605cf 100644 --- a/src/main/java/calculator/domain/Delimiter.java +++ b/src/main/java/calculator/domain/Delimiter.java @@ -6,17 +6,18 @@ import calculator.message.ErrorMessage; public class Delimiter { + private static final Pattern CUSTOM_PATTERN = Pattern.compile("//(.*?)\\\\?n(.*)", Pattern.DOTALL); + private final String regex; - private final String pattern = "//(.*)\\\\n(.*)"; - private Delimiter (String regax) { - this.regex = regax; + private Delimiter (String regex) { + this.regex = regex; } public static Delimiter of(String value) { - Pattern p = Pattern.compile("//(.*)\\\\\\\\n(.*)",Pattern.DOTALL); - Matcher m = p.matcher(value); - if (m.matches()) { - String custom = m.group(1); + Matcher matcher = CUSTOM_PATTERN.matcher(value); + + if (matcher.matches()) { + String custom = matcher.group(1); if(custom.isEmpty()) { //커스텀 구분자가 빈 문자열이면 예외처리 throw new IllegalArgumentException(ErrorMessage.DELIMITER_MISSING); } @@ -25,8 +26,8 @@ public static Delimiter of(String value) { return new Delimiter("[,\n]"); } public String extractNumbers(String value) { - Matcher m = Pattern.compile(pattern, Pattern.DOTALL).matcher(value); - return m.matches() ? m.group(2) : value; + Matcher matcher = CUSTOM_PATTERN.matcher(value); + return matcher.matches() ? matcher.group(2) : value; } public String getRegex() { return regex; diff --git a/src/main/java/calculator/domain/Separator.java b/src/main/java/calculator/domain/Separator.java index 2cd9dfaba4..630382e608 100644 --- a/src/main/java/calculator/domain/Separator.java +++ b/src/main/java/calculator/domain/Separator.java @@ -11,15 +11,20 @@ public class Separator { private final List numbers; public Separator(String value) { - this.delimiter = Delimiter.of(value); - this.numbers = parseNumbers(delimiter.extractNumbers(value)); + this.delimiter = Delimiter.of(value);//구분자 객체 생성 + this.numbers = parseNumbers(delimiter.extractNumbers(value)); //숫자 변환 } private List parseNumbers(String nums) { List result = new ArrayList<>(); for (String token: nums.split(delimiter.getRegex())){ if(!token.isEmpty()) { - int num = Integer.parseInt(token); + int num; + try{ + num = Integer.parseInt(token); + }catch (NumberFormatException e){ //숫자가 아닌 경우 예외처리 + throw new IllegalArgumentException(ErrorMessage.ENTERED_NON_NUMERIC_VALUE); + } //음수인경우 예외처리 if (num < 0) { throw new IllegalArgumentException(ErrorMessage.NEGATIVE_NUMBER_NOT_ALLOWED); From 44725d5cfde9011af90df3ec3947a0bfbf6be80a Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:17:09 +0900 Subject: [PATCH 12/16] =?UTF-8?q?test:=20Separator=20class=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/calculator/SeparatorTest.java | 55 +++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/test/java/calculator/SeparatorTest.java diff --git a/src/test/java/calculator/SeparatorTest.java b/src/test/java/calculator/SeparatorTest.java new file mode 100644 index 0000000000..13dfc3ad6d --- /dev/null +++ b/src/test/java/calculator/SeparatorTest.java @@ -0,0 +1,55 @@ +package calculator; + + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import calculator.domain.Separator; +import calculator.message.ErrorMessage; + +class SeparatorTest { + + @DisplayName("기본 구분자 - 쉼표") + @Test + void basic_separator_comma() { + Separator separator = new Separator("1,2,3"); + List numbers = separator.getNumbers(); + assertEquals(List.of(1, 2, 3), numbers); + } + + @DisplayName("기본 구분자 - 개행") + @Test + void basic_separator_newline() { + Separator separator = new Separator("1\n2\n3"); + List numbers = separator.getNumbers(); + assertEquals(List.of(1, 2, 3), numbers); + } + + @DisplayName("기본 구분자 - 세미클론") + @Test + void basic_seperator_semicolon() { + Separator separator = new Separator("//;\\n1;2;3"); + List numbers = separator.getNumbers(); + assertEquals(List.of(1, 2, 3), numbers); + } + + @DisplayName("음수값 예외") + @Test + void exception_negative_number() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> new Separator("1,-2,3")); + assertEquals(ErrorMessage.NEGATIVE_NUMBER_NOT_ALLOWED, exception.getMessage()); + } + + @DisplayName("숫자가 아닌 값이 들어왔을때 예외 처리") + @Test + void exception_entered_non_numeric_value() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> new Separator("1,a,3")); + assertEquals(ErrorMessage.ENTERED_NON_NUMERIC_VALUE, exception.getMessage()); + } +} From f588916e4bf8712ef6e671bf5f8cf35af0d15b04 Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Mon, 20 Oct 2025 18:43:01 +0900 Subject: [PATCH 13/16] =?UTF-8?q?docs:=20README.md=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ac81979d72..d88e6209f9 100644 --- a/README.md +++ b/README.md @@ -37,18 +37,23 @@ BUILD SUCCESSFUL in 0s - 사용자가 잘못된 값을 입력한 경우 `IllegalArgumentException` 을 발생시킨 후 애플리케이션은 종료 되어야 한다. ### 🛠️ 구현 기능 목록 -- [ ] 사용자로부터 문자열을 입력받는다 +- [x] 사용자로부터 문자열을 입력받는다 - 문자열이 구분자와 양수로 구성되어 있는지 확인한다. + - 양수가 아닌 음수가 입력된 경우 -> `NEGATIVE_NUMBER_NOT_ALLOWED` 예외 발생 + - 아무것도 입력하지않은 경우에는 -> 0 을 반환한다. + - 공백만 입력하거나 공백을 문자에 포함한 경우의 -> `NEGATIVE_NUMBER_NOT_ALLOWED`예외 발생 + - 숫자가 아닌 값을 입력할 경우 ->`ENTERED_NON_NUMERIC_VALUE`예외 발생 - 문자열이 잘못된 값일 경우 예외를 발생 시킨 후 애플리케이션을 종료한다. -- [ ] 커스텀 구분자를 지정한다 +- [x] 커스텀 구분자를 지정한다 - 커스텀 구분자는 문자열 앞부분의 `//` 와 `\n` 사이에 위치하는 문자를 커스텀 구분자로 사용한다. - (예) `//;\n1;2;3` 과 같이 값을 입력할 경우 커스텀 구분자는 `;` 이며 결과값은 6이 반환되어야 한다. - 커스텀 구분자는 1글자 이상일 수 있다. - (예) `//;.\n1;.2;.3 ` 일때 커스텀 구분자는 `;. ` + - 빈 문자열(1글자 이하)인 경우 -> `DELIMITER_MISSING`예외 발생 - 기본 구분자 `,` `;` -- [ ] 문자열을 구분자를 기준으로 분리한다. -- [ ] 구분자를 기준으로 분리한 각 숫자를 합친다. -- [ ] 각 숫자를 합한 결과를 출력한다. +- [x] 문자열을 구분자를 기준으로 분리한다. +- [x] 구분자를 기준으로 분리한 각 숫자를 합친다. +- [x] 각 숫자를 합한 결과를 출력한다. **실행 결과 예시** ``` @@ -68,4 +73,4 @@ BUILD SUCCESSFUL in 0s ### 📚 라이브러리 - `camp.nextstep.edu.missionutils `에서 제공하는 Console API를 사용하여 구현해야 한다. - - 사용자가 입력하는 값은 camp.nextstep.edu.missionutils.Console의 readLine()을 활용한다 \ No newline at end of file + - 사용자가 입력하는 값은 `camp.nextstep.edu.missionutils.Console`의 readLine()을 활용한다 From abb6742564b712a98cf5324ab8ac7b73b64132db Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:33:39 +0900 Subject: [PATCH 14/16] =?UTF-8?q?refactor:=20Delimiter=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=BB=A4=EC=8A=A4=ED=85=80=20=EA=B5=AC?= =?UTF-8?q?=EB=B6=84=EC=9E=90=20=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/calculator/domain/Delimiter.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/calculator/domain/Delimiter.java b/src/main/java/calculator/domain/Delimiter.java index b462c605cf..1582022f3f 100644 --- a/src/main/java/calculator/domain/Delimiter.java +++ b/src/main/java/calculator/domain/Delimiter.java @@ -6,7 +6,7 @@ import calculator.message.ErrorMessage; public class Delimiter { - private static final Pattern CUSTOM_PATTERN = Pattern.compile("//(.*?)\\\\?n(.*)", Pattern.DOTALL); + private static final Pattern CUSTOM_PATTERN = Pattern.compile("//(.*?)\\\\n(.*) | //(.*?)\\n(.*)", Pattern.DOTALL); //group(1) / (2) : 커스텀 / 숫자 , group(3) / (4) : 커스텀 / 숫자 private final String regex; @@ -17,17 +17,21 @@ public static Delimiter of(String value) { Matcher matcher = CUSTOM_PATTERN.matcher(value); if (matcher.matches()) { - String custom = matcher.group(1); - if(custom.isEmpty()) { //커스텀 구분자가 빈 문자열이면 예외처리 + String custom = matcher.group(1) != null ? matcher.group(1) : matcher.group(3); + if(custom == null || custom.isEmpty()) { //커스텀 구분자가 빈 문자열이면 예외처리 throw new IllegalArgumentException(ErrorMessage.DELIMITER_MISSING); } return new Delimiter(Pattern.quote(custom)); } return new Delimiter("[,\n]"); } + //구분자 이후 숫자 문자열만 public String extractNumbers(String value) { Matcher matcher = CUSTOM_PATTERN.matcher(value); - return matcher.matches() ? matcher.group(2) : value; + if (matcher.matches()) { + return matcher.group(2) != null ? matcher.group(2) : matcher.group(4); + } + return value; } public String getRegex() { return regex; From ae63548a7818e3f04820ca64819ffda369b313bc Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:54:41 +0900 Subject: [PATCH 15/16] =?UTF-8?q?refactor:=20Separator=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EA=B0=92=20=EA=B2=80=EC=A6=9D=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81=20=EB=B0=8F=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/calculator/domain/Delimiter.java | 12 ++-- src/test/java/calculator/SeparatorTest.java | 63 +++++++++++++------ 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/src/main/java/calculator/domain/Delimiter.java b/src/main/java/calculator/domain/Delimiter.java index 1582022f3f..b462c605cf 100644 --- a/src/main/java/calculator/domain/Delimiter.java +++ b/src/main/java/calculator/domain/Delimiter.java @@ -6,7 +6,7 @@ import calculator.message.ErrorMessage; public class Delimiter { - private static final Pattern CUSTOM_PATTERN = Pattern.compile("//(.*?)\\\\n(.*) | //(.*?)\\n(.*)", Pattern.DOTALL); //group(1) / (2) : 커스텀 / 숫자 , group(3) / (4) : 커스텀 / 숫자 + private static final Pattern CUSTOM_PATTERN = Pattern.compile("//(.*?)\\\\?n(.*)", Pattern.DOTALL); private final String regex; @@ -17,21 +17,17 @@ public static Delimiter of(String value) { Matcher matcher = CUSTOM_PATTERN.matcher(value); if (matcher.matches()) { - String custom = matcher.group(1) != null ? matcher.group(1) : matcher.group(3); - if(custom == null || custom.isEmpty()) { //커스텀 구분자가 빈 문자열이면 예외처리 + String custom = matcher.group(1); + if(custom.isEmpty()) { //커스텀 구분자가 빈 문자열이면 예외처리 throw new IllegalArgumentException(ErrorMessage.DELIMITER_MISSING); } return new Delimiter(Pattern.quote(custom)); } return new Delimiter("[,\n]"); } - //구분자 이후 숫자 문자열만 public String extractNumbers(String value) { Matcher matcher = CUSTOM_PATTERN.matcher(value); - if (matcher.matches()) { - return matcher.group(2) != null ? matcher.group(2) : matcher.group(4); - } - return value; + return matcher.matches() ? matcher.group(2) : value; } public String getRegex() { return regex; diff --git a/src/test/java/calculator/SeparatorTest.java b/src/test/java/calculator/SeparatorTest.java index 13dfc3ad6d..9176d76ca4 100644 --- a/src/test/java/calculator/SeparatorTest.java +++ b/src/test/java/calculator/SeparatorTest.java @@ -1,12 +1,15 @@ package calculator; +import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import calculator.domain.Separator; import calculator.message.ErrorMessage; @@ -14,19 +17,27 @@ class SeparatorTest { @DisplayName("기본 구분자 - 쉼표") - @Test - void basic_separator_comma() { - Separator separator = new Separator("1,2,3"); + @ParameterizedTest + @ValueSource(strings = {"1,2,3", ",1,2,3"}) + void basic_separator_comma(String inputs) { + Separator separator = new Separator(inputs); List numbers = separator.getNumbers(); - assertEquals(List.of(1, 2, 3), numbers); + + assertThat(numbers).isEqualTo(List.of(1, 2, 3)); } @DisplayName("기본 구분자 - 개행") - @Test - void basic_separator_newline() { - Separator separator = new Separator("1\n2\n3"); + @ParameterizedTest + @ValueSource(strings = {"1\n2\n3","\n1\n2\n3"}) + void basic_separator_newline(String inputs) { + //given + + //when + Separator separator = new Separator(inputs); List numbers = separator.getNumbers(); - assertEquals(List.of(1, 2, 3), numbers); + + //then + assertThat(numbers).isEqualTo(List.of(1, 2, 3)); } @DisplayName("기본 구분자 - 세미클론") @@ -38,18 +49,34 @@ void basic_seperator_semicolon() { } @DisplayName("음수값 예외") - @Test - void exception_negative_number() { - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, - () -> new Separator("1,-2,3")); - assertEquals(ErrorMessage.NEGATIVE_NUMBER_NOT_ALLOWED, exception.getMessage()); + @ParameterizedTest + @ValueSource(strings = {"1,-2,3","-1,1,1","-1,-2,3"}) + void exception_negative_number(String inputs) { + //given + + //when, then + assertThatThrownBy(() -> new Separator(inputs)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage(ErrorMessage.NEGATIVE_NUMBER_NOT_ALLOWED); + + // IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + // () -> new Separator("1,-2,3")); + // assertEquals(ErrorMessage.NEGATIVE_NUMBER_NOT_ALLOWED, exception.getMessage()); } @DisplayName("숫자가 아닌 값이 들어왔을때 예외 처리") - @Test - void exception_entered_non_numeric_value() { - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, - () -> new Separator("1,a,3")); - assertEquals(ErrorMessage.ENTERED_NON_NUMERIC_VALUE, exception.getMessage()); + @ParameterizedTest + @ValueSource(strings = {"//;\\na;2;3","a,2:3","@,2:3" }) + void exception_entered_non_numeric_value(String inputs) { + //given + + //when, then + assertThatThrownBy(() -> new Separator(inputs)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage(ErrorMessage.ENTERED_NON_NUMERIC_VALUE); + + // IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + // () -> new Separator("1,a,3")); + // assertEquals(ErrorMessage.ENTERED_NON_NUMERIC_VALUE, exception.getMessage()); } } From 765c712910cf5b6c3fd42127dfaecc97e6f00d79 Mon Sep 17 00:00:00 2001 From: Hwa Young Yang <110398814+sanchaehwa@users.noreply.github.com> Date: Mon, 20 Oct 2025 22:05:16 +0900 Subject: [PATCH 16/16] =?UTF-8?q?test:=20Delimiter=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/calculator/DelimiterTest.java | 54 +++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/test/java/calculator/DelimiterTest.java diff --git a/src/test/java/calculator/DelimiterTest.java b/src/test/java/calculator/DelimiterTest.java new file mode 100644 index 0000000000..e2a26610dd --- /dev/null +++ b/src/test/java/calculator/DelimiterTest.java @@ -0,0 +1,54 @@ +package calculator; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.regex.Pattern; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import calculator.domain.Delimiter; +import calculator.message.ErrorMessage; + +class DelimiterTest { + + @DisplayName("기본 구분자 사용") + @Test + void defaultDelimiterTest() { + Delimiter delimiter = Delimiter.of("1,2,3"); + assertEquals("[,\n]", delimiter.getRegex()); + + String numbers = delimiter.extractNumbers("1,2,3"); + assertEquals("1,2,3", numbers); + } + + @DisplayName("커스텀 구분자 적용") + @ParameterizedTest + @ValueSource(strings = {"//;\\n1;2;3", "//*\\n4*5*6"}) + void customDelimiterTest(String input) { + Delimiter delimiter = Delimiter.of(input); + + String numbers = delimiter.extractNumbers(input); + assertNotNull(numbers); + assertTrue(Pattern.matches("\\d+(;|\\*)\\d+(;|\\*)\\d+", numbers)); + } + + @DisplayName("커스텀 구분자가 비어있으면 예외") + @ParameterizedTest + @ValueSource(strings = {"//\\n1,2,3", "//\\n"}) + void emptyCustomDelimiterTest(String input) { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> Delimiter.of(input)); + assertEquals(ErrorMessage.DELIMITER_MISSING, exception.getMessage()); + } + + @DisplayName("잘못된 포맷 입력 시 기본 처리") + @Test + void invalidFormatTest() { + Delimiter delimiter = Delimiter.of("1#2#3"); + assertEquals("[,\n]", delimiter.getRegex()); + assertEquals("1#2#3", delimiter.extractNumbers("1#2#3")); + } +}