Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 59 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,59 @@
# javascript-calculator-precourse
# javascript-calculator-precourse

문자열 덧셈 계산기 실행 후 필요한 기능을 다음과 같이 정리해보았습니다.

### 1. 구분자 지정 기능

- 기본 구분자 `","`와 `":"`를 설정.
- 사용자가 커스텀 구분자를 입력했을 경우 이를 적용하도록 함.

---

### 2. 입력 요청 및 수신 기능

- `Console.readLineAsync("덧셈할 문자열을 입력해 주세요." \n)`로 사용자 입력을 받음.

---

### 3. 입력 검증 기능

입력 문자열을 검증하는 두 단계의 검증 로직을 포함함.

**_검증 1. 커스텀 구분자 헤더 검사_**

- 입력이 `"//"`로 시작하고 `"\n"`이 있는 경우 헤더 존재로 판단, 없다면 **검증 2** 수행.
- 헤더 내부 문자열의 길이가 1이 아니면 **검증 실패**.
- 헤더 내부 문자열이 숫자이면 **검증 실패**.
- 검증 통과 시 헤더에서 지정한 구분자로 기존 구분자 목록을 대체.
- 이후 **검증 2** 수행.

**_검증 2. 숫자 및 구분자 형식 검사_**

- 지정된 구분자 이외의 문자가 존재하면 **검증 실패**.
- 구분자로 문자열 분리.
- 빈 값이 있다면(구분자 사이에 숫자가 없음) **검증 실패**

---

### 4. 에러 처리 기능

- **검증 실패** 시 `[ERROR]`로 시작하는 에러 메시지를 throw.
- 이후 프로그램 **즉시 종료**.

---

### 5. 합산 기능

- 기본 혹은 커스텀 문자열로 분리된 숫자들의 합을 계산.

---

### 6. 결과 출력 기능

- `"결과 : <숫자들의 합>"`을 `Console.print()`로 출력.

---

### 8. 프로그램 종료

- 모든 연산이 완료되면 프로그램 정상 종료.
114 changes: 113 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -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;