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
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,27 @@
# javascript-calculator-precourse
# javascript-calculator-precourse

## 기능 목록

### 입력받기

- [x] 입력받은 문자열에서 구분자를 기준으로 숫자를 추출한다.

### 구분자 정하기

- [x] 기본 구분자: 쉼표(`,`), 콜론(`:`)
- [x] 커스텀 구분자: `//`와 `\\n` 사이에 위치하는 문자

### 검증하기

- [x] 올바른 커스텀 구분자인지 검증한다(문자 길이 1 확인)
- [x] 올바른 숫자 형식인지 검증한다(숫자만 허용)
- [x] 양수인지 검사한다(음수 불허용)

### 계산하기

- [x] 추출한 숫자들을 모두 더한다.

### 출력하기

- [x] 계산 결과를 `결과 : {숫자}` 형식으로 출력한다.
- [x] 에러 발생 시 `[ERROR] {에러메시지}` 형식으로 출력한다.
28 changes: 27 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
import { InputManager } from "./InputManager.js";
import { Separator } from "./Separator.js";
import { Validator } from "./Validator.js";
import { OutputManager } from "./OutputManager.js";
import { MissionUtils } from "@woowacourse/mission-utils";

class App {
async run() {}
async run() {
try {
const rawInput = await InputManager.getInput();
const { separator, numStrs } = Separator.parse(rawInput);
Validator.validateSeparators(separator);
const escapedSeparators = separator.map((sep) =>
sep.replace(/[\\^$.|?*+()[\]{}-]/g, "\\$&")
); // 정규표현식 내에서 특수문자는 이스케이프되어야 함.
const regex = new RegExp(`[${escapedSeparators.join("")}]`);
const numbers = numStrs.split(regex).filter((n) => n.trim() !== "");
Validator.validateNumbers(numbers);
Validator.validatePositiveNumbers(numbers);
const addResult = numbers
.map((s) => +s.trim())
.reduce((r, n) => r + n, 0);
OutputManager.print(addResult);
} catch (err) {
OutputManager.errorPrint(err.message);
throw err;
}
}
}

export default App;
9 changes: 9 additions & 0 deletions src/InputManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { MissionUtils } from "@woowacourse/mission-utils";

export class InputManager {
static async getInput() {
return await MissionUtils.Console.readLineAsync(
"덧셈할 문자열을 입력해 주세요.\n"
);
}
}
11 changes: 11 additions & 0 deletions src/OutputManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { MissionUtils } from "@woowacourse/mission-utils";

export class OutputManager {
static print(result) {
MissionUtils.Console.print(`결과 : ${result}`);
}

static errorPrint(errMsg) {
MissionUtils.Console.print(`${errMsg}`);
}
}
14 changes: 14 additions & 0 deletions src/Separator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export class Separator {
static parse(rawInput) {
const separator = [",", ":"]; // 기본 구분자
const customSeparators = [...rawInput.matchAll(/\/\/(.+?)\\n/g)].map(
(m) => m[1]
); // 커스텀 구분자
if (customSeparators.length) {
separator.push(...customSeparators);
}
// 숫자 부분 추출
const numStrs = rawInput.replace(/\/\/(.+?)\\n/, "");
return { separator, numStrs };
}
}
34 changes: 34 additions & 0 deletions src/Validator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export class Validator {
// 유효한 구분자인지 검사 (문자인지 확인)
static validateSeparators(separator) {
if (!Array.isArray(separator) || separator.length === 0) {
throw new Error("[ERROR] 구분자는 하나 이상이여야 합니다.");
}

separator.forEach((sep) => {
if (typeof sep !== "string" || sep.length !== 1) {
throw new Error("[ERROR] 각 구분자는 하나의 문자여야 합니다.");
}
});
}

// 유효한 숫자인지 검사 (숫자 형식 검증)
static validateNumbers(numStrs) {
numStrs.forEach((numStr) => {
const trimmed = numStr.trim();
if (trimmed === "" || isNaN(Number(trimmed))) {
throw new Error("[ERROR] 올바른 숫자 형식이 아닙니다.");
}
});
}

// 양수인지 검사
static validatePositiveNumbers(numStrs) {
numStrs.forEach((numStr) => {
const num = Number(numStr.trim());
if (num < 0) {
throw new Error("[ERROR] 음수는 허용되지 않습니다.");
}
});
}
}