Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e4116d1
덧셈할 문자열 입력
dong279 Mar 21, 2026
979ee54
빈문자열 입력 시 0 반환
dong279 Mar 21, 2026
99b1691
커스텀 구분자로 문자열을 분리 하고 각 숫자를 합산하는 로직 구현
dong279 Mar 21, 2026
98e4aa5
음수 입력 시 예외 처리 추가
dong279 Mar 21, 2026
f960611
'//'와'|n'사이의 문자를 커스텀 구분자로 추출하는 로직 구현 완료. + Pattern.quote()로 특수문자도 구분자…
dong279 Mar 21, 2026
6a24e8a
결과물 출력 추가
dong279 Mar 21, 2026
e8e4c21
결과물 출력 수정
dong279 Mar 21, 2026
5c1261a
readme 수정
dong279 Mar 23, 2026
1da11a7
mvc 패턴을 도입하여 폴더와 파일 구조를 개편 했습니다
dong279 Mar 24, 2026
fb1f65d
기존 폰더 구조에서 calculator의 mvc 패턴을 명시하기 위해 model, controller, view 폴더를 ca…
dong279 Mar 24, 2026
f0a82c1
feat: InputView, OutputView view 패키지로 입력과 출력을 분리함
dong279 Mar 24, 2026
dc69590
feat: Validator 클래스 생성으로 커스텀 구분자 및 음수 검증 분리
dong279 Mar 24, 2026
d40a7eb
feat: StringParser 클래스를 생성하여 구분자 파싱 로직 분리
dong279 Mar 24, 2026
50ebce1
feat: StringCalculator 클래스를 생성하여 숫자 합산 계산 로직 분리
dong279 Mar 24, 2026
7a51054
Validator validateNotNegative의 예외 문자 뒤 '.'->':' 수정
dong279 Mar 24, 2026
06f62a2
- StringCalulator를 static 직접 호출에서 생성자 주입(DI)로 변경
dong279 May 12, 2026
93e0ec8
- 문자열 토큰을 받아 정수로 변환하는 책임을 PostiveNumber로 이동함
dong279 May 12, 2026
b4283ad
- String[] 대신 List<PositiveNumber>를 감싸는 일급 컬렉션 도입
dong279 May 12, 2026
4bc81ab
- ,및: 기본 구분자 파싱 로직을 별도 클래스로 분리
dong279 May 12, 2026
94cada3
- 커스텀 구분자 파싱 로직을 별도 클래스로 분리 (SRP)
dong279 May 12, 2026
c1bd3f3
- null/empty 입력 처리를 Calculator에서 Parser 단계로 이동
dong279 May 12, 2026
1861404
- static 메서드를 인스턴스 메서드로 전환 (OOP 준수)
dong279 May 12, 2026
984b5de
- StringCalculator를 static 직접 호출에서 생성자 주입(DI)으로 변경
dong279 May 12, 2026
46768f0
- POSIX 표준에 따라 파일 끝 개행 추가
dong279 May 12, 2026
b38a2b8
- POSIX 표준에 따라 파일 끝 개행 추가
dong279 May 12, 2026
111c4b2
- StringParser 역할을 DefaultDelimiterParser, CustomDelimiterParser, Exp…
dong279 May 12, 2026
5e03a5d
- PositiveNumberTest: 변환, 음수/비숫자 예외 검증
dong279 May 12, 2026
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
69 changes: 56 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,50 +11,48 @@

### **진행 방식**

- 미션은 **과제 진행 요구 사항**, **기능 요구 사항**, **프로그래밍 요구 사항** 세 가지로 구성되어 있다.
- 미션은 **과제 진행 요구 사항**, **기능 요구 사항**, **프로그래밍 요구 사항** 세 가지로 구성되어 있다.
- 세 개의 요구 사항을 만족하기 위해 노력한다. 특히 기능을 구현하기 전에 기능 목록을 만들고, 기능 단위로 커밋 하는 방식으로 진행한다.
- **기능 요구 사항에 기재되지 않은 내용은 스스로 판단하여 구현한다.**

### **미션 제출 방법**

- 미션 구현을 완료한 후 GitHub을 통해 제출해야 한다.
- GitHub을 활용한 제출 방법은 [프리코스 과제 제출](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 문서를 참고해 제출한다.
- GitHub을 활용한 제출 방법은 [프리코스 과제 제출](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 문서를 참고해 제출한다.

### **과제 제출 전 체크 리스트**

- 기능을 올바르게 구현했더라도 **요구 사항에 명시된 출력 형식을 따르지 않으면 0점**을 받게 된다.
- 기능을 올바르게 구현했더라도 **요구 사항에 명시된 출력 형식을 따르지 않으면 0점**을 받게 된다.
- 기능 구현을 완료한 후 아래 가이드에 따라 모든 테스트가 성공적으로 실행되는지 확인한다.
- **테스트가 실패하면 점수가 0점**이 되므로 제출하기 전에 반드시 확인한다.

### **테스트 실행 가이드**

- 터미널에서 `java -version`을 실행하여 Java 버전이 21인지 확인한다. Eclipse 또는 IntelliJ IDEA와 같은 IDE에서 Java 21로 실행되는지 확인한다.
- 터미널에서 Mac 또는 Linux 사용자의 경우 `./gradlew clean test` 명령을 실행하고, Windows 사용자의 경우 `gradlew.bat clean test` 또는 `.\gradlew.bat clean test` 명령을 실행할 때 모든 테스트가 아래와 같이 통과하는지 확인한다.

- 터미널에서 `java -version`을 실행하여 Java 버전이 21인지 확인한다. Eclipse 또는 IntelliJ IDEA와 같은 IDE에서 Java 21로 실행되는지 확인한다.
- 터미널에서 Mac 또는 Linux 사용자의 경우 `./gradlew clean test` 명령을 실행하고, Windows 사용자의 경우 `gradlew.bat clean test` 또는 `.\gradlew.bat clean test` 명령을 실행할 때 모든 테스트가 아래와 같이 통과하는지 확인한다.
```
BUILD SUCCESSFUL in 0s

```

---

# **문자열 덧셈 계산기**

## **과제 진행 요구 사항**
- **기능을 구현하기 전 `README.md`에 구현할 기능 목록을 정리**해 추가한다.
- Git의 커밋 단위는 앞 단계에서 `README.md`에 정리한 기능 목록 단위로 추가한다.
- [AngularJS Git Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153)을 참고해 커밋 메시지를 작성한다.
- **기능을 구현하기 전 `README.md`에 구현할 기능 목록을 정리**해 추가한다.
- Git의 커밋 단위는 앞 단계에서 `README.md`에 정리한 기능 목록 단위로 추가한다.
- [AngularJS Git Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153)을 참고해 커밋 메시지를 작성한다.
- 자세한 과제 진행 방법은 프리코스 진행 가이드 문서를 참고한다.

## **기능 요구 사항**

입력한 문자열에서 숫자를 추출하여 더하는 계산기를 구현한다.

- 쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환한다.
- 예: "" => 0, "1,2" => 3, "1,2,3" => 6, "1,2:3" => 6
- 예: "" => 0, "1,2" => 3, "1,2,3" => 6, "1,2:3" => 6
- 앞의 기본 구분자(쉼표, 콜론) 외에 커스텀 구분자를 지정할 수 있다. 커스텀 구분자는 문자열 앞부분의 "//"와 "\n" 사이에 위치하는 문자를 커스텀 구분자로 사용한다.
- 예를 들어 "//;\n1;2;3"과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다.
- 사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`을 발생시킨 후 애플리케이션은 종료되어야 한다.
- 예를 들어 "//;\n1;2;3"과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다.
- 사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`을 발생시킨 후 애플리케이션은 종료되어야 한다.

### **입출력 요구 사항**

Expand All @@ -65,12 +63,57 @@ BUILD SUCCESSFUL in 0s
### **출력**

- 덧셈 결과
```
결과 : 6
```

### **실행 결과 예시**
```
덧셈할 문자열을 입력해 주세요.
1,2:3
결과 : 6
```

## **프로그래밍 요구 사항**

- JDK 21 버전에서 실행 가능해야 한다.
- 프로그램 실행의 시작점은 `Application`의 `main()`이다.
- `build.gradle` 파일은 변경할 수 없으며, **제공된 라이브러리 이외의 외부 라이브러리는 사용하지 않는다.**
- 프로그램 종료 시 `System.exit()`를 호출하지 않는다.
- 프로그래밍 요구 사항에서 달리 명시하지 않는 한 파일, 패키지 등의 이름을 바꾸거나 이동하지 않는다.
- 자바 코드 컨벤션을 지키면서 프로그래밍한다.
- 기본적으로 [Java Style Guide](https://github.com/woowacourse/woowacourse-docs/blob/main/styleguide/java)를 원칙으로 한다.

### **라이브러리**

- `camp.nextstep.edu.missionutils`에서 제공하는 `Console` API를 사용하여 구현해야 한다.
- 사용자가 입력하는 값은 `camp.nextstep.edu.missionutils.Console`의 `readLine()`을 활용한다.

---

## **기능 목록**

### 입력
- [x] 덧셈할 문자열 입력 받기

### 계산
- [x] 빈 문자열 입력 시 0 반환
- [x] 쉼표(,), 콜론(:) 기본 구분자로 숫자 분리 후 합산
- [x] 커스텀 구분자(`//[구분자]\n`) 파싱 후 합산

### 예외 처리
- [x] 음수 입력 시 IllegalArgumentException 발생
- [x] 숫자가 아닌 값 입력 시 IllegalArgumentException 발생
- [x] 잘못된 커스텀 구분자 형식 입력 시 IllegalArgumentException 발생

### 출력
- [x] `결과 : {합계}` 형식으로 결과 출력
```

README.md 전체 교체 후:
```
git add .
git commit -m "docs: README 기능 목록 작성"
### **실행 결과 예시**

```
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/calculator/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
package calculator;

import camp.nextstep.edu.missionutils.Console;
import calculator.controller.CalculatorController;
import calculator.model.StringCalculator;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
try {
CalculatorController controller = new CalculatorController(new StringCalculator());
controller.run();
} finally {
Console.close();
}
}
}
19 changes: 19 additions & 0 deletions src/main/java/calculator/controller/CalculatorController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package calculator.controller;

import calculator.model.StringCalculator;
import calculator.view.InputView;
import calculator.view.OutputView;

public class CalculatorController {
private final StringCalculator calculator;

public CalculatorController(StringCalculator calculator) {
this.calculator = calculator;
}

public void run(){
String input = InputView.read();
int result = calculator.calculate(input); // 도메인 예외는 여기서 위로 전파
OutputView.printResult(result);
}
}
23 changes: 23 additions & 0 deletions src/main/java/calculator/model/Numbers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package calculator.model;

import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class Numbers {
private final List<PositiveNumber> values;

public Numbers(List<PositiveNumber> values) {
this.values = List.copyOf(values);
}

public static Numbers empty() {
return new Numbers(Collections.emptyList());
}

public int sum(){
return values.stream()
.mapToInt(PositiveNumber::getValue)
.sum();
}
}
26 changes: 26 additions & 0 deletions src/main/java/calculator/model/PositiveNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package calculator.model;

public class PositiveNumber {
private final int value;

public PositiveNumber(String token) {
this.value = parse(token);
}

private int parse(String token) {
int number;
try{
number = Integer.parseInt(token.trim());
} catch (NumberFormatException e) {
throw new IllegalArgumentException("숫자가 아닌 값입니다."+token);
}
if (number < 0) {
throw new IllegalArgumentException("음수는 입력할 수 없습니다." + number);
}
return number;
}
public int getValue() {
return value;
}

}
12 changes: 12 additions & 0 deletions src/main/java/calculator/model/StringCalculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package calculator.model;

import calculator.model.parser.ExpressionParser;

public class StringCalculator {
private final ExpressionParser parser = new ExpressionParser();

public int calculate(String input) {
Numbers numbers = parser.parse(input);
return numbers.sum();
}
}
33 changes: 33 additions & 0 deletions src/main/java/calculator/model/parser/CustomDelimiterParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package calculator.model.parser;

import calculator.model.Numbers;
import calculator.model.PositiveNumber;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class CustomDelimiterParser {
private static final String PREFIX = "//"; // 상수명 의미 명확화
private static final String SUFFIX = "\\n"; // 상수명 의미 명확화

public boolean supports(String input){
return input.startsWith(PREFIX);
}

public Numbers parse(String input){
int suffixIndex = input.indexOf(SUFFIX); // newlineIndex → suffixIndex
if (suffixIndex < 0){ // Validator 대신 내부 검증
throw new IllegalArgumentException("잘못된 커스텀 구분자 형식입니다.");
}
String custom = input.substring(PREFIX.length(), suffixIndex);
String numberPart = input.substring(suffixIndex + SUFFIX.length());
String regex = "[,:]|" + Pattern.quote(custom);

List<PositiveNumber> list = Arrays.stream(numberPart.split(regex))
.map(PositiveNumber::new)
.collect(Collectors.toList());
return new Numbers(list);
}
}
19 changes: 19 additions & 0 deletions src/main/java/calculator/model/parser/DefaultDelimiterParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package calculator.model.parser;

import calculator.model.Numbers;
import calculator.model.PositiveNumber;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class DefaultDelimiterParser {
private static final String DELIMITER = "[,:]";

public Numbers parse(String input) {
List<PositiveNumber> list = Arrays.stream(input.split(DELIMITER))
.map(PositiveNumber::new)
.collect(Collectors.toList());
return new Numbers(list);
}
}
18 changes: 18 additions & 0 deletions src/main/java/calculator/model/parser/ExpressionParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package calculator.model.parser;

import calculator.model.Numbers;

public class ExpressionParser {
private final CustomDelimiterParser customParser = new CustomDelimiterParser();
private final DefaultDelimiterParser defaultParser = new DefaultDelimiterParser();

public Numbers parse(String input) {
if (input == null || input.isEmpty()){
return Numbers.empty();
}
if (customParser.supports(input)){
return customParser.parse(input);
}
return defaultParser.parse(input);
}
}
10 changes: 10 additions & 0 deletions src/main/java/calculator/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package calculator.view;

import camp.nextstep.edu.missionutils.Console;

public class InputView {
public static String read() {
System.out.println("덧셈할 문자열을 입력해 주세요.");
return Console.readLine();
}
}
7 changes: 7 additions & 0 deletions src/main/java/calculator/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package calculator.view;

public class OutputView {
public static void printResult(int result) {
System.out.println("결과 : " + result);
}
}
Loading