diff --git a/README.md b/README.md index 13420b29..0a1278ef 100644 --- a/README.md +++ b/README.md @@ -1 +1,59 @@ -# javascript-calculator-precourse \ No newline at end of file +# javascript-calculator-precourse + +문자열 덧셈 계산기 실행 후 필요한 기능을 다음과 같이 정리해보았습니다. + +### 1. 구분자 지정 기능 + +- 기본 구분자 `","`와 `":"`를 설정. +- 사용자가 커스텀 구분자를 입력했을 경우 이를 적용하도록 함. + +--- + +### 2. 입력 요청 및 수신 기능 + +- `Console.readLineAsync("덧셈할 문자열을 입력해 주세요." \n)`로 사용자 입력을 받음. + +--- + +### 3. 입력 검증 기능 + +입력 문자열을 검증하는 두 단계의 검증 로직을 포함함. + +**_검증 1. 커스텀 구분자 헤더 검사_** + +- 입력이 `"//"`로 시작하고 `"\n"`이 있는 경우 헤더 존재로 판단, 없다면 **검증 2** 수행. +- 헤더 내부 문자열의 길이가 1이 아니면 **검증 실패**. +- 헤더 내부 문자열이 숫자이면 **검증 실패**. +- 검증 통과 시 헤더에서 지정한 구분자로 기존 구분자 목록을 대체. +- 이후 **검증 2** 수행. + +**_검증 2. 숫자 및 구분자 형식 검사_** + +- 지정된 구분자 이외의 문자가 존재하면 **검증 실패**. +- 구분자로 문자열 분리. +- 빈 값이 있다면(구분자 사이에 숫자가 없음) **검증 실패** + +--- + +### 4. 에러 처리 기능 + +- **검증 실패** 시 `[ERROR]`로 시작하는 에러 메시지를 throw. +- 이후 프로그램 **즉시 종료**. + +--- + +### 5. 합산 기능 + +- 기본 혹은 커스텀 문자열로 분리된 숫자들의 합을 계산. + +--- + +### 6. 결과 출력 기능 + +- `"결과 : <숫자들의 합>"`을 `Console.print()`로 출력. + +--- + +### 8. 프로그램 종료 + +- 모든 연산이 완료되면 프로그램 정상 종료. diff --git a/src/App.js b/src/App.js index 091aa0a5..5c548f54 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,117 @@ +import { Console } from "@woowacourse/mission-utils"; +class Calculator { + constructor() { + this.basicSeparators = ",:"; + this.customSeparator = null; + } + + validateHeader(userInput) { + if (userInput == null || userInput === "") { + return ""; + } + + 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; + } + + if (userInput.startsWith("//")) { + throw new Error( + "잘못된 커스텀 구분자 형식입니다. - 커스텀 구분자 입력 형식은 '//<구분자>\\n'입니다." + ); + } + 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; + } + + 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("잘못된 입력 형식입니다. - 숫자 이외의 문자가 포함됨"); + } + } + } + + 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 { - async run() {} + constructor() { + this.calculator = new Calculator(); + } + async run() { + try { + const userInput = await Console.readLineAsync( + "덧셈할 문자열을 입력해 주세요. \n" + ); + const result = this.calculator.calculate(userInput); + Console.print(`결과 : ${result}`); + } catch (err) { + const errorMessage = `[ERROR] ${err.message}`; + throw new Error(errorMessage); + } + } } export default App;