diff --git a/README.md b/README.md index 13420b29..1ea6bae7 100644 --- a/README.md +++ b/README.md @@ -1 +1,31 @@ -# javascript-calculator-precourse \ No newline at end of file +# javascript-calculator-precourse +# 1주차 - 문자열 덧셈 계산기 + +## ⚙️ 간단한 프로젝트 실행 흐름 +1. 안내 문구를 출력한다. +2. 사용자 입력을 수신한다. +3. 입력 문자열을 parser로 넘겨 숫자 배열로 변환한다. +4. 숫자 배열을 validator로 검증한다. +5. 검증 통과 배열을 calculator로 합산한다. +6. 합산 결과를 지정된 포맷으로 출력한다. +7. 프로세스를 종료한다. + + +## 🔧 구현할 기능 목록 + +### 1. parser (문자열 -> 숫자 배열 반환) +- [X] 기본 구분자(, :) 분리 및 숫자 배열 변환 +- [X] 커스텀 구분자 지정(문자열 앞부분의 "//", "\n") + +### 2. validator (숫자 배열 유효성 검사) +- [X] 숫자가 아닌 값이 포함된 경우 검증 +- [X] 양수가 아닌 값인 경우 검증 + +### 3. calculator (합산) +- [X] 빈 배열 합산 시 0 반환 +- [X] 그 외 숫자 배열 합산 + +### 4. App.js (전체 통합 테스트) +- [X] 모든 모듈 연동 +- [X] `App.run()` 실행 로직 완성 +- [X] `AplicationTest.js` 테스트 확인 \ No newline at end of file diff --git a/src/App.js b/src/App.js index 091aa0a5..b23bdb6e 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,23 @@ +import { MissionUtils } from "@woowacourse/mission-utils"; +import { InputParser } from "./InputParser.js"; +import { InputValidator } from "./InputValidator.js"; +import { Calculator } from "./Calculator.js"; + class App { - async run() {} + async run() { + try { + const input = await MissionUtils.Console.readLineAsync("덧셈할 문자열을 입력해 주세요.\n"); + + const numbers = InputParser.parse(input); + InputValidator.validate(numbers); + const result = Calculator.sum(numbers); + + MissionUtils.Console.print(`결과 : ${result}`) + } catch (error) { + MissionUtils.Console.print(error.message); + throw error; + } + } } export default App; diff --git a/src/Calculator.js b/src/Calculator.js new file mode 100644 index 00000000..6e821db8 --- /dev/null +++ b/src/Calculator.js @@ -0,0 +1,12 @@ +export class Calculator { + static sum(numbers) { + // 빈 배열인 경우 0 반환 + if (!numbers || numbers.length === 0){ + return 0; + } + + // 그 외 숫자 배열인 경우 모든 숫자 합산 + const total = numbers.reduce((acc, cur) => acc + cur, 0); + return total; + } +} \ No newline at end of file diff --git a/src/InputParser.js b/src/InputParser.js new file mode 100644 index 00000000..d878bc50 --- /dev/null +++ b/src/InputParser.js @@ -0,0 +1,36 @@ +export class InputParser { + static parse(input) { + // 입력이 비어있거나 공백인 경우 + const raw = (input || "").trim(); + if (raw.length === 0) { + return []; + } + + // 기본 구분자: 쉼표(,)와 콜론(:) + let delimiters = [",", ":"]; + let numbersPart = raw; + + // 커스텀 구분자 + if (raw.startsWith("//")) { + const match = + raw.match(/^\/\/(.)\n(.*)/s) || // 실제 줄바꿈 + raw.match(/^\/\/(.)\\n(.*)/s); // 문자열 리터럴 "\n" + if (!match) { + throw new Error("[ERROR] 잘못된 커스텀 구분자 형식입니다."); + } + const [, custom, rest] = match; + delimiters = [",", ":", custom]; + numbersPart = rest; + } + + const escaped = delimiters.map((d) => d.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')); + const regex = new RegExp(`(?:${escaped.join("|")})`, "g"); + + // 숫자 배열로 변환 + return numbersPart + .split(regex) + .map((token) => token.trim()) + .filter((token) => token.length > 0) + .map((token) => Number(token)); // 숫자로 변환 + } +} \ No newline at end of file diff --git a/src/InputValidator.js b/src/InputValidator.js new file mode 100644 index 00000000..7ee6b6af --- /dev/null +++ b/src/InputValidator.js @@ -0,0 +1,18 @@ +export class InputValidator { + static validate(numbers) { + // 숫자가 아닌 값이 포함된 경우 + const hasNonNumber = numbers.some((n) => + typeof n !== "number" || isNaN(n)); + if (hasNonNumber) { + throw new Error("[ERROR] 숫자가 아닌 값이 포함되어 있습니다."); + } + + // 양수가 아닌 값(0 또는 음수) + const hasNegative = numbers.some((n) => n <= 0); + if (hasNegative) { + throw new Error("[ERROR] 양수가 아닌 값이 포함되어 있습니다."); + } + + return true; + } +} \ No newline at end of file