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

## 구현할 기능 목록
1. **입력 기능**: 문자열 입력 받기
2. **구분자 처리 기능**: 기본 구분자(쉼표, 콜론)와 필요시 커스텀 구분자를 사용하여 숫자 분리
3. **덧셈 기능**: 분리된 숫자들의 합 계산
4. **출력 기능**: 계산 결과 출력
27 changes: 26 additions & 1 deletion src/main/java/calculator/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
package calculator;

import java.util.Arrays;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
// 사용자 입력을 처리하는 객체 생성
InputHandler inputHandler = new InputHandler();
// 문자열 계산기를 처리하는 객체 생성
StringCalculator calculator = new StringCalculator();
// 메시지 출력을 처리하는 객체 생성
ResultPrinter printer = new ResultPrinter();

// 문자열 계산기를 사용하여 합계 계산
try {
// 사용자 입력 받기 Console.readLine() 사용
String userInput = inputHandler.getInput();
// "\n" 이스케이프 처리
userInput = userInput.replace("\\n", "\n");

//덧셈 계산
int result = calculator.calculate(userInput);

// 결과 출력
printer.printResult(result);
} catch (IllegalArgumentException e) {
// 오류 재던짐으로 인해 종료
printer.printError(e.getMessage());
throw e;
}
}
}
70 changes: 70 additions & 0 deletions src/main/java/calculator/DelimiterHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package calculator;

import java.util.regex.Pattern;

public class DelimiterHandler {

private static final String DEFAULT_DELIMITER = ",:";
private static final String CUSTOM_DELIMITER_PREFIX = "//";
private static final String LINE_SEPARATOR = "\n";


/**
* 구분자와 숫자 부분을 담는 레코드 클래스
*
* @param delimiters 모든 구분자를 포함한 문자열
* @param numbersPart 실제 계산할 숫자들이 포함된 부분
*/
private record ParseResult(String delimiters, String numbersPart) {
}


/**
* 입력 문자열을 구분자와 숫자 부분으로 파싱
*
* @param input 파싱할 입력 문자열
* @return 구분자와 숫자 부분이 분리된 객체
* @throws IllegalArgumentException 구분자 형식이 잘못된 경우
*/
private ParseResult parseInput(String input) {
String delimiters = DEFAULT_DELIMITER;
String numbersPart = input;

// 사용자 정의 구분자가 있는 경우 처리
if (input.startsWith(CUSTOM_DELIMITER_PREFIX)) {
int newlineIndex = input.indexOf(LINE_SEPARATOR);
if (newlineIndex == -1) {
throw new IllegalArgumentException("잘못된 구분자 형식입니다.");
}
// 사용자 정의 구분자 추출
String customDelimiter = input.substring(CUSTOM_DELIMITER_PREFIX.length(), newlineIndex);
// 사용자 정의 구분자와 기본 구분자 결합
delimiters = customDelimiter + delimiters;
// 숫자 부분만 추출
numbersPart = input.substring(newlineIndex + 1);
}

return new ParseResult(delimiters, numbersPart);
}

/**
* 입력 문자열에서 구분자를 파싱하고 숫자 부분을 분리하여 배열로 반환
* @param input 처리할 입력 문자열
* @return 구분자로 분리된 숫자 문자열 배열
*/
public String[] parseAndSplitInput(String input) {

// 구분자와 숫자 부분 분리
ParseResult result = parseInput(input);
// 구분자 문자들을 OR 연산자(|)로 연결된 정규식으로 변환
StringBuilder regexBuilder = new StringBuilder();
for (char ch : result.delimiters.toCharArray()) {
// 특수문자를 정규식에서 사용할 수 있도록 이스케이프 처리
regexBuilder.append(Pattern.quote(String.valueOf(ch))).append("|");
}
// 마지막 | 문자 제거
String regex = regexBuilder.substring(0, regexBuilder.length() - 1);
// 정규식 패턴으로 문자열 분할하여 반환
return result.numbersPart.split(regex);
}
}
17 changes: 17 additions & 0 deletions src/main/java/calculator/InputHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package calculator;

import camp.nextstep.edu.missionutils.Console;

public class InputHandler {
// 문자열 입력
private static final String PROMPT_MESSAGE = "덧셈할 문자열을 입력해 주세요.";
// 안내 메시지 출력
private void printPrompt() {
System.out.println(PROMPT_MESSAGE);
}
public String getInput() {
printPrompt();
return Console.readLine();
}

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

public class ResultPrinter {
private static final String RESULT_FORMAT = "결과 : %d";

// 계산 결과 출력
public void printResult(int result) {
System.out.printf(RESULT_FORMAT + "\n", result);
}

// 오류 메시지 출력
public void printError(String message) {
System.out.println(message);
}

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

public class StringCalculator {

private final DelimiterHandler delimiterHandler;

//DelimiterHandler 객체 생성(커스텀/기본 구분자 처리를 위해)
public StringCalculator() {
this.delimiterHandler = new DelimiterHandler();
}

//입력 문자열을 받아 숫자를 합산
public int calculate(String input) {
if (input == null || input.trim().isEmpty()) {
throw new IllegalArgumentException("Empty string cannot be calculated.");
}

String[] numbers = delimiterHandler.parseAndSplitInput(input);
return sumNumbers(numbers);
}

// 문자열 배열을 숫자로 변환하고 합산
private int sumNumbers(String[] numbers) {
int sum = 0;

for (String numStr : numbers) {
if (numStr.isEmpty()) continue;

int number = parseToPositiveInteger(numStr);
sum += number;
}

return sum;
}

// 문자열을 양수 정수로 변환
private int parseToPositiveInteger(String numStr) {
int number;
try {
number = Integer.parseInt(numStr);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("잘못된 숫자 형식: " + numStr);
}

if (number < 0) {
throw new IllegalArgumentException("음수는 허용되지 않습니다: " + number);
}

return number;
}

}
47 changes: 47 additions & 0 deletions src/test/java/calculator/ApplicationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,55 @@ class ApplicationTest extends NsTest {
assertThatThrownBy(() -> runException("-1,2,3"))
.isInstanceOf(IllegalArgumentException.class)
);
}@Test
void 기본_구분자_테스트() {
assertSimpleTest(() -> {
run("1,2:3");
assertThat(output()).contains("결과 : 6");
});
}

@Test
void 빈_문자열_테스트() {
assertSimpleTest(() ->
assertThatThrownBy(() -> runException(""))
.isInstanceOf(IllegalArgumentException.class)
);
}

@Test
void 숫자형식_오류_테스트() {
assertSimpleTest(() ->
assertThatThrownBy(() -> runException("1,2,a"))
.isInstanceOf(IllegalArgumentException.class)
);
}

@Test
void 잘못된_구분자_형식_테스트() {
assertSimpleTest(() ->
assertThatThrownBy(() -> runException("//;1,2,3"))
.isInstanceOf(IllegalArgumentException.class)
);
}

@Test
void 복합_구분자_사용_테스트() {
assertSimpleTest(() -> {
run("1,2:3");
assertThat(output()).contains("결과 : 6");
});
}

@Test
void 커스텀_구분자와_기본구분자_혼합_테스트() {
assertSimpleTest(() -> {
run("//;\\n1;2,3:4");
assertThat(output()).contains("결과 : 10");
});
}


@Override
public void runMain() {
Application.main(new String[]{});
Expand Down