From c7887800b47292f669b05c7b5bc19bdc77bf7854 Mon Sep 17 00:00:00 2001 From: bbbbmo Date: Mon, 20 Oct 2025 13:11:25 +0900 Subject: [PATCH 01/11] =?UTF-8?q?docs:=20README=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 13420b29..97019de0 100644 --- a/README.md +++ b/README.md @@ -1 +1,62 @@ -# javascript-calculator-precourse \ No newline at end of file +# javascript-calculator-precourse + +문자열 덧셈 계산기 실행 후 필요한 기능을 다음과 같이 정리해보았습니다. + +### 1. 구분자 지정 기능 + +- 기본 구분자 `","`와 `":"`를 설정. +- 사용자가 커스텀 구분자를 입력했을 경우 이를 적용하도록 함. + +--- + +### 2. 입력 요청 및 수신 기능 + +- `Console.print("덧셈할 문자열을 입력해 주세요.")` +- `Console.readLineAsync()`로 사용자 입력을 받음. + +--- + +### 3. 입력 검증 기능 + +입력 문자열을 검증하는 두 단계의 검증 로직을 포함함. + +**_검증 1. 커스텀 구분자 헤더 검사_** + +- 입력이 `"//"`로 시작하고 `"\n"`이 있는 경우 헤더 존재로 판단, 없다면 **검증 2** 수행. +- 헤더 내부 문자열의 길이가 1이 아니면 **검증 실패**. +- 헤더 내부 문자열이 숫자이면 **검증 실패**. +- 검증 통과 시 헤더에서 지정한 구분자로 기존 구분자 목록을 대체. +- 이후 **검증 2** 수행. + +**_검증 2. 숫자 및 구분자 형식 검사_** + +- 지정된 구분자 이외의 문자가 존재하면 **검증 실패**. +- 구분자로 문자열 분리. +- 빈 값이 있다면(구분자 사이에 숫자가 없음) **검증 실패** + +--- + +### 4. 에러 처리 기능 + +- **검증 실패** 시 `[ERROR]`로 시작하는 에러 메시지를 출력. +- 이후 프로그램 **즉시 종료**. + +--- + +### 5. 정상 처리 기능 + +- 검증이 통과되면 사용자 입력 문자열을 그대로 출력 (`Console.print()`). +- 구분자를 기준으로 숫자를 분리하여 정수 리스트 생성. +- 숫자들의 합을 계산. + +--- + +### 6. 결과 출력 기능 + +- `"결과: <숫자들의 합>"`을 `Console.print()`로 출력. + +--- + +### 8. 프로그램 종료 + +- 모든 연산이 완료되면 프로그램 정상 종료. From 08f013d10ccee6cbf89d44c643e486bf2de2ee05 Mon Sep 17 00:00:00 2001 From: bbbbmo Date: Mon, 20 Oct 2025 21:37:50 +0900 Subject: [PATCH 02/11] =?UTF-8?q?docs:=20Console=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B2=B0=EA=B3=BC?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20README=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 97019de0..1348d453 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,7 @@ ### 2. 입력 요청 및 수신 기능 -- `Console.print("덧셈할 문자열을 입력해 주세요.")` -- `Console.readLineAsync()`로 사용자 입력을 받음. +- `Console.readLineAsync("덧셈할 문자열을 입력해 주세요." \n)`로 사용자 입력을 받음. --- @@ -38,14 +37,13 @@ ### 4. 에러 처리 기능 -- **검증 실패** 시 `[ERROR]`로 시작하는 에러 메시지를 출력. +- **검증 실패** 시 `[ERROR]`로 시작하는 에러 메시지를 throw. - 이후 프로그램 **즉시 종료**. --- ### 5. 정상 처리 기능 -- 검증이 통과되면 사용자 입력 문자열을 그대로 출력 (`Console.print()`). - 구분자를 기준으로 숫자를 분리하여 정수 리스트 생성. - 숫자들의 합을 계산. @@ -53,7 +51,7 @@ ### 6. 결과 출력 기능 -- `"결과: <숫자들의 합>"`을 `Console.print()`로 출력. +- `"결과 : <숫자들의 합>"`을 `Console.print()`로 출력. --- From c49e0f05fdb24e9c5caa1d0df92e66c7f67e7aaf Mon Sep 17 00:00:00 2001 From: bbbbmo Date: Mon, 20 Oct 2025 21:42:55 +0900 Subject: [PATCH 03/11] =?UTF-8?q?=E2=9C=A8=20feat:=20=EA=B8=B0=EB=B3=B8=20?= =?UTF-8?q?=EA=B5=AC=EB=B6=84=EC=9E=90(,=20:)=EC=99=80=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20=EA=B5=AC=EB=B6=84=EC=9E=90=EB=A5=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=9E=90=EB=A1=9C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/App.js b/src/App.js index 091aa0a5..3a2af63b 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,14 @@ +class Calculator { + constructor() { + this.basicSeparators = ",:"; + this.customSeparator = null; + } +} + class App { + constructor() { + this.calculator = new Calculator(); + } async run() {} } From d02f0239cacde430bf013d5b1f12e0230dbfb214 Mon Sep 17 00:00:00 2001 From: bbbbmo Date: Mon, 20 Oct 2025 21:48:55 +0900 Subject: [PATCH 04/11] =?UTF-8?q?=E2=9C=A8=20feat:=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=9E=85=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(Console.readLineAsync)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index 3a2af63b..bfe12255 100644 --- a/src/App.js +++ b/src/App.js @@ -1,3 +1,5 @@ +import { Console } from "@woowacourse/mission-utils"; + class Calculator { constructor() { this.basicSeparators = ",:"; @@ -9,7 +11,12 @@ class App { constructor() { this.calculator = new Calculator(); } - async run() {} + async run() { + const userInput = await Console.readLineAsync( + "덧셈할 문자열을 입력해 주세요. \n" + ); + Console.print(`입력값: ${userInput}`); + } } export default App; From 76947f24914a99c4a7ec3f263f0dd9557c2f3704 Mon Sep 17 00:00:00 2001 From: bbbbmo Date: Mon, 20 Oct 2025 21:55:37 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat(validate):=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=20=EA=B5=AC=EB=B6=84=EC=9E=90=20=ED=97=A4=EB=8D=94=20?= =?UTF-8?q?=EC=A1=B4=EC=9E=AC=20=EC=8B=9C=20=EA=B2=80=EC=A6=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/App.js b/src/App.js index bfe12255..7514a631 100644 --- a/src/App.js +++ b/src/App.js @@ -5,6 +5,27 @@ class Calculator { this.basicSeparators = ",:"; this.customSeparator = null; } + + validateHeader(userInput) { + if (userInput == null || userInput === "") { + return ""; + } + + const headerRegex = new RegExp(/^\/\/(.)\\n/); + const header = userInput.match(headerRegex); + if (header) { + this.customSeparator = header[1]; + const headerlessInput = userInput.substring(5); + return headerlessInput; + } + + if (userInput.startsWith("//")) { + throw new Error( + "잘못된 커스텀 구분자 형식입니다. - 커스텀 구분자 입력 형식은 '//<구분자>\\n'입니다." + ); + } + return userInput; + } } class App { @@ -12,10 +33,17 @@ class App { this.calculator = new Calculator(); } async run() { - const userInput = await Console.readLineAsync( - "덧셈할 문자열을 입력해 주세요. \n" - ); - Console.print(`입력값: ${userInput}`); + try { + const userInput = await Console.readLineAsync( + "덧셈할 문자열을 입력해 주세요. \n" + ); + + const result = this.calculator.validateHeader(userInput); + Console.print(`검증 결과: ${result}`); + } catch (err) { + const errorMessage = `[ERROR] ${err.message}`; + throw new Error(errorMessage); + } } } From ec1bb7e5b557bbd270b9dbb2a914fc5e7479cea9 Mon Sep 17 00:00:00 2001 From: bbbbmo Date: Mon, 20 Oct 2025 21:58:08 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat(validate):=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=20=EA=B5=AC=EB=B6=84=EC=9E=90=EA=B0=80=20=EC=88=AB?= =?UTF-8?q?=EC=9E=90=EC=9D=BC=20=EC=8B=9C=20=EC=97=90=EB=9F=AC=20=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 --- src/App.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/App.js b/src/App.js index 7514a631..ed0712ce 100644 --- a/src/App.js +++ b/src/App.js @@ -14,6 +14,11 @@ class Calculator { const headerRegex = new RegExp(/^\/\/(.)\\n/); const header = userInput.match(headerRegex); if (header) { + if (/[0-9]/.test(header[1])) { + throw new Error( + "잘못된 커스텀 구분자 형식입니다. - 커스텀 구분자는 숫자가 될 수 없습니다." + ); + } this.customSeparator = header[1]; const headerlessInput = userInput.substring(5); return headerlessInput; From 453510d0a0c9388f20aaef2289aad57c0a5c621b Mon Sep 17 00:00:00 2001 From: bbbbmo Date: Mon, 20 Oct 2025 22:01:53 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feat(validate):=20=EC=A7=80=EC=A0=95?= =?UTF-8?q?=EB=90=9C=20=EA=B5=AC=EB=B6=84=EC=9E=90=20=EC=9D=B4=EC=99=B8?= =?UTF-8?q?=EC=9D=98=20=EB=AC=B8=EC=9E=90=20=EC=A1=B4=EC=9E=AC=20=EC=97=AC?= =?UTF-8?q?=EB=B6=80=EB=A5=BC=20=EA=B2=80=EC=A6=9D=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=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/App.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index ed0712ce..ff33da45 100644 --- a/src/App.js +++ b/src/App.js @@ -31,6 +31,22 @@ class Calculator { } return userInput; } + + validateInput(input) { + if (input === "") { + return ""; + } + + const separator = this.customSeparator + ? this.customSeparator + : this.basicSeparators; + const allowedRegex = new RegExp(`^[0-9${separator}]+$`); + + if (!allowedRegex.test(input)) { + throw new Error("잘못된 입력 형식입니다. - 구분자 외 다른 문자가 존재"); + } + return input; + } } class App { @@ -43,7 +59,8 @@ class App { "덧셈할 문자열을 입력해 주세요. \n" ); - const result = this.calculator.validateHeader(userInput); + const validatedInput = this.calculator.validateHeader(userInput); + const result = this.calculator.validateInput(validatedInput); Console.print(`검증 결과: ${result}`); } catch (err) { const errorMessage = `[ERROR] ${err.message}`; From 221d84701e171c6cacf7812fba1674d7648b67bb Mon Sep 17 00:00:00 2001 From: bbbbmo Date: Mon, 20 Oct 2025 22:07:20 +0900 Subject: [PATCH 08/11] =?UTF-8?q?feat(validate):=20=EA=B5=AC=EB=B6=84?= =?UTF-8?q?=EC=9E=90=EB=A1=9C=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=EB=90=9C=20=EC=9A=94=EC=86=8C=EB=A5=BC=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=ED=95=98=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/App.js b/src/App.js index ff33da45..8af2d9f2 100644 --- a/src/App.js +++ b/src/App.js @@ -47,6 +47,45 @@ class Calculator { } return input; } + + splitBySeparators(input) { + if (input === "") { + return []; + } + + const splitRegex = new RegExp(`[${this.basicSeparators}]`); + return this.customSeparator + ? input.split(this.customSeparator) + : input.split(splitRegex); + } + + splitBySeparators(input) { + if (input === "") { + return []; + } + + const splitRegex = new RegExp(`[${this.basicSeparators}]`); + return this.customSeparator + ? input.split(this.customSeparator) + : input.split(splitRegex); + } + + validateArray(arr) { + if (arr.length === 0) { + return; + } + + if (arr.some((element) => element === "")) { + throw new Error("잘못된 입력 형식입니다. - 구분자 사이에 숫자가 없음"); + } + + const intRegex = /^\d+$/; + for (const element of arr) { + if (!intRegex.test(element)) { + throw new Error("잘못된 입력 형식입니다. - 숫자 이외의 문자가 포함됨"); + } + } + } } class App { From a89b328710a947fd3a46d59fe9738d771899b996 Mon Sep 17 00:00:00 2001 From: bbbbmo Date: Mon, 20 Oct 2025 22:10:42 +0900 Subject: [PATCH 09/11] =?UTF-8?q?docs:=20README=20=EC=A4=91=EB=B3=B5?= =?UTF-8?q?=EB=90=9C=20=EB=82=B4=EC=9A=A9=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1348d453..0a1278ef 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,9 @@ --- -### 5. 정상 처리 기능 +### 5. 합산 기능 -- 구분자를 기준으로 숫자를 분리하여 정수 리스트 생성. -- 숫자들의 합을 계산. +- 기본 혹은 커스텀 문자열로 분리된 숫자들의 합을 계산. --- From 6244aab4e89c1a5ae206e4b888284ef493a426c1 Mon Sep 17 00:00:00 2001 From: bbbbmo Date: Mon, 20 Oct 2025 22:13:41 +0900 Subject: [PATCH 10/11] =?UTF-8?q?feat:=20=EA=B5=AC=EB=B6=84=EC=9E=90?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC=EB=90=9C=20=EC=88=AB=EC=9E=90=20?= =?UTF-8?q?=ED=95=A9=EC=82=B0=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index 8af2d9f2..9943c093 100644 --- a/src/App.js +++ b/src/App.js @@ -86,6 +86,10 @@ class Calculator { } } } + + sum(numberArr) { + return numberArr.reduce((acc, num) => Number(acc) + Number(num), 0); + } } class App { @@ -100,7 +104,11 @@ class App { const validatedInput = this.calculator.validateHeader(userInput); const result = this.calculator.validateInput(validatedInput); - Console.print(`검증 결과: ${result}`); + const splitedStrArray = this.calculator.splitBySeparators(result); + this.calculator.validateArray(splitedStrArray); + const numberArray = splitedStrArray.map(Number); + const sum = this.calculator.sum(numberArray); + Console.print(`결과 : ${sum}`); } catch (err) { const errorMessage = `[ERROR] ${err.message}`; throw new Error(errorMessage); From 246af9b548a5eedc7f1c3461089eb2820a65ff23 Mon Sep 17 00:00:00 2001 From: bbbbmo Date: Mon, 20 Oct 2025 22:16:46 +0900 Subject: [PATCH 11/11] =?UTF-8?q?refactor:=20=EC=88=9C=EC=88=98=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=ED=98=95=ED=83=9C=EB=A1=9C=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/App.js b/src/App.js index 9943c093..5c548f54 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,4 @@ import { Console } from "@woowacourse/mission-utils"; - class Calculator { constructor() { this.basicSeparators = ",:"; @@ -59,17 +58,6 @@ class Calculator { : input.split(splitRegex); } - splitBySeparators(input) { - if (input === "") { - return []; - } - - const splitRegex = new RegExp(`[${this.basicSeparators}]`); - return this.customSeparator - ? input.split(this.customSeparator) - : input.split(splitRegex); - } - validateArray(arr) { if (arr.length === 0) { return; @@ -90,6 +78,22 @@ class Calculator { sum(numberArr) { return numberArr.reduce((acc, num) => Number(acc) + Number(num), 0); } + + calculate(userInput) { + try { + const normalized = (userInput ?? "").replace(/[^\S\n]+/g, ""); + const headerlessInput = this.validateHeader(normalized); + + const validatedInput = this.validateInput(headerlessInput); + + const splitedStrArray = this.splitBySeparators(validatedInput); + this.validateArray(splitedStrArray); + + return this.sum(splitedStrArray); + } catch (err) { + throw new Error(err.message); + } + } } class App { @@ -101,14 +105,8 @@ class App { const userInput = await Console.readLineAsync( "덧셈할 문자열을 입력해 주세요. \n" ); - - const validatedInput = this.calculator.validateHeader(userInput); - const result = this.calculator.validateInput(validatedInput); - const splitedStrArray = this.calculator.splitBySeparators(result); - this.calculator.validateArray(splitedStrArray); - const numberArray = splitedStrArray.map(Number); - const sum = this.calculator.sum(numberArray); - Console.print(`결과 : ${sum}`); + const result = this.calculator.calculate(userInput); + Console.print(`결과 : ${result}`); } catch (err) { const errorMessage = `[ERROR] ${err.message}`; throw new Error(errorMessage);