diff --git a/README.md b/README.md
index bd90ef0..71a20c9 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,46 @@
-# java-calculator-precourse
\ No newline at end of file
+# java-calculator-precourse
+
+다시 시작하는 우테코 프리코스의 꿈...이랄까.....
+
+
+ 과제 세부 내용
+
+## 과제
+
+입력한 문자열에서 숫자를 추출하여 더하는 계산기를 구현한다.
+
+- 쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환한다.
+ - 예: "" => 0, "1,2" => 3, "1,2,3" => 6, "1,2:3" => 6
+- 앞의 기본 구분자(쉼표, 콜론) 외에 커스텀 구분자를 지정할 수 있다. 커스텀 구분자는 문자열 앞부분의 "//"와 "\n" 사이에 위치하는 문자를 커스텀 구분자로 사용한다.
+ - 예를 들어 "//;\n1;2;3"과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다.
+- 사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`을 발생시킨 후 애플리케이션은 종료되어야 한다.
+
+### 입출력
+
+- 입력
+ - 구분자와 양수로 구성된 문자열
+- 출력
+ - 덧셈 결과
+
+ex)
+
+```
+덧셈할 문자열을 입력해 주세요.
+1,2:3
+결과 : 6
+```
+
+
+
+## Business Logic
+
+- 입력을 받는다
+- 구분자가 있을 경우 추출한다
+- 모두 더한다
+
+## 구현할 기능 목록
+
+- [ ] 입출력
+- [ ] 구분자 추출
+- [ ] 수식 구성
+- [ ] 수식 계산
diff --git a/src/main/java/calculator/AppConfig.java b/src/main/java/calculator/AppConfig.java
new file mode 100644
index 0000000..40692a5
--- /dev/null
+++ b/src/main/java/calculator/AppConfig.java
@@ -0,0 +1,28 @@
+package calculator;
+
+import calculator.controller.CalculatorController;
+import calculator.model.Expression;
+import calculator.view.InputView;
+import calculator.view.OutputView;
+
+public class AppConfig {
+ public InputView inputView() {
+ return new InputView();
+ }
+
+ public OutputView outputView() {
+ return new OutputView();
+ }
+
+ public Expression expression() {
+ return new Expression();
+ }
+
+ public CalculatorController calculatorController() {
+ return new CalculatorController(
+ this.inputView(),
+ this.outputView(),
+ this.expression()
+ );
+ }
+}
diff --git a/src/main/java/calculator/Application.java b/src/main/java/calculator/Application.java
index 573580f..f9e2f88 100644
--- a/src/main/java/calculator/Application.java
+++ b/src/main/java/calculator/Application.java
@@ -1,7 +1,15 @@
package calculator;
+import calculator.controller.CalculatorController;
+
public class Application {
+ static AppConfig appConfig;
+ static CalculatorController calculatorController;
+
public static void main(String[] args) {
- // TODO: 프로그램 구현
+ appConfig = new AppConfig();
+ calculatorController = appConfig.calculatorController();
+
+ calculatorController.run();
}
}
diff --git a/src/main/java/calculator/controller/CalculatorController.java b/src/main/java/calculator/controller/CalculatorController.java
new file mode 100644
index 0000000..075fccd
--- /dev/null
+++ b/src/main/java/calculator/controller/CalculatorController.java
@@ -0,0 +1,26 @@
+package calculator.controller;
+
+import calculator.model.Expression;
+import calculator.view.InputView;
+import calculator.view.OutputView;
+
+public class CalculatorController {
+ InputView inputView;
+ OutputView outputView;
+ Expression expression;
+
+ public CalculatorController(
+ InputView inputView, OutputView outputView, Expression expression
+ ) {
+ this.inputView = inputView;
+ this.outputView = outputView;
+ this.expression = expression;
+ }
+
+ public void run() {
+ String line = inputView.getExpression();
+ expression = Expression.parse(line);
+ int result = expression.calculate();
+ outputView.printResult(result);
+ }
+}
diff --git a/src/main/java/calculator/model/Expression.java b/src/main/java/calculator/model/Expression.java
new file mode 100644
index 0000000..2a22aee
--- /dev/null
+++ b/src/main/java/calculator/model/Expression.java
@@ -0,0 +1,70 @@
+package calculator.model;
+
+import calculator.utils.ExceptionConstants;
+import calculator.utils.Validator;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+public class Expression {
+ private HashSet operators;
+ private String expression;
+
+ private static final List DEFAULT_SEPARATOR = Arrays.asList(':', ',');
+ private static final String OR_DELIMITER = "|";
+ private static final String CUSTOM_SEPARATOR_REGEX = "^//(.)\\\\n(.*)";
+
+ private static final int CUSTOM_SEPARATOR_INDEX = 1;
+ private static final int EXPRESSION_INDEX = 2;
+
+ public static Expression parse(String line) {
+ Expression expression = new Expression();
+
+ line = line.trim();
+ line = expression.extractOperators(line);
+ expression.expression = line;
+
+ return expression;
+ }
+
+ public HashSet getOperators() {
+ return operators;
+ }
+
+ public String getExpression() {
+ return expression;
+ }
+
+ public int calculate() {
+ List results = Arrays.stream(expression.split(getOperatorsRegex())).toList();
+ results.forEach(Validator::validatePositiveInt);
+ try {
+ return results.stream()
+ .mapToInt(Integer::parseInt)
+ .reduce(0, Math::addExact);
+ } catch (Exception exception) {
+ throw new IllegalArgumentException(
+ ExceptionConstants.INVALID_EXPRESSION.getMessage() + expression, exception);
+ }
+ }
+
+ private String extractOperators(String line) {
+ this.operators = new HashSet<>();
+ this.operators.addAll(DEFAULT_SEPARATOR);
+ Matcher matcher = Pattern.compile(CUSTOM_SEPARATOR_REGEX).matcher(line);
+ if (matcher.find()) {
+ operators.add(matcher.group(CUSTOM_SEPARATOR_INDEX).charAt(0));
+ return matcher.group(EXPRESSION_INDEX);
+ }
+ return line;
+ }
+
+ private String getOperatorsRegex() {
+ return operators.stream()
+ .map((ch) -> Pattern.quote(ch.toString())) // \같은 문자 처리
+ .collect(Collectors.joining(OR_DELIMITER));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/calculator/utils/ExceptionConstants.java b/src/main/java/calculator/utils/ExceptionConstants.java
new file mode 100644
index 0000000..6773e42
--- /dev/null
+++ b/src/main/java/calculator/utils/ExceptionConstants.java
@@ -0,0 +1,16 @@
+package calculator.utils;
+
+public enum ExceptionConstants {
+ INVALID_EXPRESSION("덧셈할 문자열을 입력해 주세요."),
+ INVALID_NUMBER_COMPOSITION("결과 : %d");
+
+ private final String message;
+
+ ExceptionConstants(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return this.message;
+ }
+}
diff --git a/src/main/java/calculator/utils/MessageConstants.java b/src/main/java/calculator/utils/MessageConstants.java
new file mode 100644
index 0000000..25d5e9e
--- /dev/null
+++ b/src/main/java/calculator/utils/MessageConstants.java
@@ -0,0 +1,16 @@
+package calculator.utils;
+
+public enum MessageConstants {
+ GUIDE_MESSAGE("덧셈할 문자열을 입력해 주세요."),
+ RESULT_MESSAGE("결과 : %d");
+
+ private final String message;
+
+ MessageConstants(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return this.message;
+ }
+}
diff --git a/src/main/java/calculator/utils/Validator.java b/src/main/java/calculator/utils/Validator.java
new file mode 100644
index 0000000..73e1217
--- /dev/null
+++ b/src/main/java/calculator/utils/Validator.java
@@ -0,0 +1,15 @@
+package calculator.utils;
+
+public class Validator {
+
+
+ public static void validatePositiveInt(String number) {
+ try {
+ if (Integer.parseInt(number) < 0) {
+ throw new NumberFormatException();
+ }
+ } catch (Exception exception) {
+ throw new IllegalArgumentException(ExceptionConstants.INVALID_NUMBER_COMPOSITION.getMessage() + number);
+ }
+ }
+}
diff --git a/src/main/java/calculator/view/InputView.java b/src/main/java/calculator/view/InputView.java
new file mode 100644
index 0000000..0d5b7ae
--- /dev/null
+++ b/src/main/java/calculator/view/InputView.java
@@ -0,0 +1,15 @@
+package calculator.view;
+
+import calculator.utils.MessageConstants;
+import camp.nextstep.edu.missionutils.Console;
+
+public class InputView {
+ public String getExpression() {
+ try {
+ System.out.println(MessageConstants.GUIDE_MESSAGE.getMessage());
+ return Console.readLine();
+ } catch (Exception exception) {
+ throw new IllegalArgumentException("Something went wrong on input process.");
+ }
+ }
+}
diff --git a/src/main/java/calculator/view/OutputView.java b/src/main/java/calculator/view/OutputView.java
new file mode 100644
index 0000000..94df46b
--- /dev/null
+++ b/src/main/java/calculator/view/OutputView.java
@@ -0,0 +1,9 @@
+package calculator.view;
+
+import calculator.utils.MessageConstants;
+
+public class OutputView {
+ public void printResult(int v) {
+ System.out.printf((MessageConstants.RESULT_MESSAGE.getMessage()) + "%n", v);
+ }
+}
diff --git a/src/test/java/calculator/ApplicationTest.java b/src/test/java/calculator/ApplicationTest.java
index 93771fb..1b2db04 100644
--- a/src/test/java/calculator/ApplicationTest.java
+++ b/src/test/java/calculator/ApplicationTest.java
@@ -1,12 +1,12 @@
package calculator;
-import camp.nextstep.edu.missionutils.test.NsTest;
-import org.junit.jupiter.api.Test;
-
import static camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import camp.nextstep.edu.missionutils.test.NsTest;
+import org.junit.jupiter.api.Test;
+
class ApplicationTest extends NsTest {
@Test
void 커스텀_구분자_사용() {
@@ -19,8 +19,8 @@ class ApplicationTest extends NsTest {
@Test
void 예외_테스트() {
assertSimpleTest(() ->
- assertThatThrownBy(() -> runException("-1,2,3"))
- .isInstanceOf(IllegalArgumentException.class)
+ assertThatThrownBy(() -> runException("-1,2,3"))
+ .isInstanceOf(IllegalArgumentException.class)
);
}
diff --git a/src/test/java/calculator/ExpressionTest.java b/src/test/java/calculator/ExpressionTest.java
new file mode 100644
index 0000000..c0d8a05
--- /dev/null
+++ b/src/test/java/calculator/ExpressionTest.java
@@ -0,0 +1,34 @@
+package calculator;
+
+import static camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import calculator.model.Expression;
+import org.junit.jupiter.api.Test;
+
+public class ExpressionTest {
+ @Test
+ void Extract_Separator() {
+ assertSimpleTest(() -> {
+ Expression expression = Expression.parse("//*\\n1*2*3");
+ assertThat(expression.getOperators()).contains('*');
+ assertThat(expression.getExpression()).isEqualTo("1*2*3");
+ });
+ }
+
+ @Test
+ void No_Separator() {
+ assertSimpleTest(() -> {
+ Expression expression = Expression.parse("1,2,3");
+ assertThat(expression.getExpression()).isEqualTo("1,2,3");
+ });
+ }
+
+ @Test
+ void Special_Separator() {
+ assertSimpleTest(() -> {
+ Expression expression = Expression.parse("//\\\\n1*2*3");
+ assertThat(expression.getOperators()).contains('\\');
+ });
+ }
+}