diff --git a/README.md b/README.md index 13420b29..0c5bff3e 100644 --- a/README.md +++ b/README.md @@ -1 +1,36 @@ -# javascript-calculator-precourse \ No newline at end of file +# javascript-calculator-precourse + +# 문자열 덧셈 계산기 기능 구현 목록 + +- 문자열 입력 받기. + - `덧셈할 문자열을 입력해 주세요.` 시작 문구 출력. + - `Console.print()` 사용. + - `Console.readLineAsync()` 사용. + +
+ +- 결과 계산하기. + + - 구분자로 분리한 숫자 배열 생성. + - 정규표현식 사용하여 `,`와 `:`으로 분리. + - 커스텀 구분자로 분리. + - 생성된 숫자 배열을 `reduce` 내장 메소드 사용하여, 합 계산.br> + +- 결과 출력하기. +- `Console.print()` 사용. + +
+ +- 예외 처리하기. + + - "[ERROR]"로 시작하는 메시지와 함께 Error를 발생. + - 커스텀 구분자 예외 처리. + - 커스텀 구분자가 문자가 아닌 경우 Error 처리. + - 커스텀 구분자 구분 표시(`\n`)가 없는 경우 Error 처리. + - 피연산자 예외 처리. + - Operands가 숫자가 아닌 경우 Error 처리. + - 구분자가 아닌 다른 문자 포함된(구분자를 잘못 입력한) 경우 Error 처리. + - 양수가 아닌 경우 Error 처리. + - 빈 문자열 입력 시, `0` 출력. + +- 애플리케이션 종료. diff --git a/package-lock.json b/package-lock.json index a1211435..bd7e7bd3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,6 +52,7 @@ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -2969,6 +2970,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001663", "electron-to-chromium": "^1.5.28", diff --git a/src/App.js b/src/App.js index 091aa0a5..c54904d2 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,83 @@ +import { Console } from "@woowacourse/mission-utils"; +import { + CALCULATOR_MESSAGE, + EMPTY_STRING, + ERROR_MESSAGE, +} from "./Constants.js"; +import { + isValidCharSeparator, + isValidCustomEndIndex, + isValidIsOperands, + isValidVaildSeparator, + isValidOperandRange, +} from "./validation.js"; + class App { - async run() {} + async run() { + await this.enterInput(); + + try { + this.calculateResult(); + this.printResult(); + } catch (error) { + throw error; + } + } + async enterInput() { + this.input = await Console.readLineAsync( + CALCULATOR_MESSAGE.CALCULATOR_START + ); + } + + printResult() { + Console.print(CALCULATOR_MESSAGE.CALCULATOR_RESULT + this.sum); + } + + calculateResult() { + const operands = this.splitInput(); + + if (operands.length === 1 && operands[0] === EMPTY_STRING) { + this.sum = 0; + return; + } + + this.validateOperands(operands); + this.sum = operands.reduce((acc, cur) => acc + Number(cur), 0); + } + + splitInput() { + if (this.input.startsWith("//")) { + const customEndIndex = this.input.indexOf("\\n"); + const separator = this.input.slice(2, customEndIndex); + const separatedInput = this.input.slice(customEndIndex + 2); + + this.validateSeperator(customEndIndex, separator); + return separatedInput.split(separator); + } + + return this.input.split(/,|:/); + } + + validateSeperator(customEndIndex, seperator) { + if (!isValidCustomEndIndex(customEndIndex)) { + throw new Error(ERROR_MESSAGE.INVALID_CUSTOM_END); + } + if (!isValidCharSeparator(seperator)) { + throw new Error(ERROR_MESSAGE.INVALID_CHARACTER); + } + } + + validateOperands(Input) { + if (!isValidIsOperands(Input)) { + throw new Error(ERROR_MESSAGE.INVALID_NUMBER); + } + if (!isValidVaildSeparator(Input)) { + throw new Error(ERROR_MESSAGE.INVALID_SEPARATOR); + } + if (!isValidOperandRange(Input)) { + throw new Error(ERROR_MESSAGE.INVALID_RANGE); + } + } } export default App; diff --git a/src/constants.js b/src/constants.js new file mode 100644 index 00000000..524343dd --- /dev/null +++ b/src/constants.js @@ -0,0 +1,12 @@ +export const CALCULATOR_MESSAGE = { + CALCULATOR_START: "덧셈할 문자열을 입력해 주세요.\n", + CALCULATOR_RESULT: "결과 : ", +}; + +export const ERROR_MESSAGE = { + INVALID_CUSTOM_END: "[ERROR] 커스텀 구분자가 정확히 지정되지 않았습니다.", + INVALID_NUMBER: "[ERROR] 숫자를 입력해주세요.", + INVALID_RANGE: "[ERROR] 양수를 입력해주세요.", +}; + +export const EMPTY_STRING = ""; diff --git a/src/validation.js b/src/validation.js new file mode 100644 index 00000000..0842359d --- /dev/null +++ b/src/validation.js @@ -0,0 +1,19 @@ +export function isValidCharSeparator(seperator) { + return seperator.length === 1 && isNaN(seperator); +} + +export function isValidCustomEndIndex(endIndex) { + return endIndex !== -1; +} + +export function isValidIsOperands(input) { + return input.every((operand) => !isNaN(parseInt(operand))); +} + +export function isValidVaildSeparator(input) { + return input.every((operand) => !Number.isNaN(Number(operand))); +} + +export function isValidOperandRange(input) { + return input.every((operand) => 0 < Number(operand)); +}