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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# java-calculator-precourse
# java-calculator-precourse
1. 정규표현식을 사용해서 문자열 구분자를 이용한 덧셈처리
48 changes: 48 additions & 0 deletions src/main/java/calculator/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,55 @@
package calculator;

import camp.nextstep.edu.missionutils.Console;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
String string = Console.readLine();
//정규표현식을 통해서 입력받은 문자열이 //(문자)\n의 형태인지 아닌지를 확인한다.
//실제개행문자(\n)가 아니기때문에 문자열 백슬래시를 이스케이프를 진행
String patternString = "^(?://(.{1})\\\\n(.*)|(?!//).*)$";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(string);
boolean isContain = matcher.matches();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정규표현식을 씀에도 함수 분리가 안돼서 불필요하게 필드가 낭비되는 것 같아요

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

동의합니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pattern이랑 matcher라는걸 방금 알았어요 ㄷㄷ 저는 코드로 하나하나 다짰는데 너무 쉽고 간편한 방법이 있었네요

if (isContain){
//구분자와 구분자를 제외한 수식 변수를 만든다
String delimiter;
String expression;
//커스텀구분자를 제작한다면 커스텀구분자가 있는 그룹과 수식이 있는 그룹으로 나눈다.
String customDelimiter = matcher.group(1);
String rest = matcher.group(2);

if (customDelimiter != null) {
//커스텀 구분자가 존재한다면 해당 값을 구분자 변수에 넣어 준다.
//수식이 있는 부분을 수식 변수에 넣어 준다.
delimiter = customDelimiter;
expression = rest;
} else {
//기본 구분자는 :와 ,인데 하나로 통일해주기 위해서 :로 통일해준다.
delimiter = ":";
expression = matcher.group(0);
expression = expression.replace(",", delimiter);
}
//구분자로 수식을 나눈다.
delimiter = Pattern.quote(delimiter);
String[] splitExpression = expression.split(delimiter);
int sum = 0;
//소수를 표현하기 위한 .이 있으면 소수가 아니라 구분자로 인식될 것이기에 소수는 없다고 생각해도 된다.
for (int i =0; i < splitExpression.length; i++){

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for 문 별다른 이유가 없다면 인덱스 접근보다 원소로 접근하는게 효율적일 것 같아요!

if (!splitExpression[i].matches("^[1-9][0-9]*$")) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 splitExpression[i].matches("^[1-9][0-9]*$")로 숫자를 검증하고 있는데,
매번 정규표현식을 컴파일하는 것보다 숫자 검증을 위한 정규표현식을 별도의 메서드로 분리하는건 어떤가요..?

//양수에는 0이 없다. 0이 나와도 에러 처리를 진행한다.
throw new IllegalArgumentException("Charactor that isn't delimiter is in this expression");
} else{
sum += Integer.parseInt(splitExpression[i]);
}
}
System.out.println("결과 : "+sum);
} else{
throw new IllegalArgumentException("Not in rule. Can't caculate this expression");
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주석에 설명적인 부분은 README.md에 정리하고 흐름적인 부분은 함수 분리로 함수명을 통해 전달하면 좋을 것 같아요

47 changes: 47 additions & 0 deletions src/test/java/calculator/ApplicationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,65 @@
class ApplicationTest extends NsTest {
@Test
void 커스텀_구분자_사용() {
//기본 테스트
assertSimpleTest(() -> {
run("//;\\n1");
assertThat(output()).contains("결과 : 1");
});
//기본 테스트
assertSimpleTest(() -> {
run("1,2:3");
assertThat(output()).contains("결과 : 6");
});
//두 자릿 수 이상의 숫자
assertSimpleTest(() -> {
run("//;\\n1;21;361");
assertThat(output()).contains("결과 : 383");
});
//두 자릿 수 이상의 숫자
assertSimpleTest(() -> {
run("//;\\n4;30;200");
assertThat(output()).contains("결과 : 234");
});
//구분자 ^로 변경
assertSimpleTest(() -> {
run("//^\\n3^7^9");
assertThat(output()).contains("결과 : 19");
});
//구분자 @로 변경
assertSimpleTest(() -> {
run("//@\\n19@8");
assertThat(output()).contains("결과 : 27");
});
}

@Test
void 예외_테스트() {
//기본 예외
assertSimpleTest(() ->
assertThatThrownBy(() -> runException("-1,2,3"))
.isInstanceOf(IllegalArgumentException.class)
);
//소수 or .구분자가 아닌 문자 사용
assertSimpleTest(() ->
assertThatThrownBy(() -> runException("1.3:3"))
.isInstanceOf(IllegalArgumentException.class)
);
//커스텀 구분자 명시하는 패턴 사이 문자가 두개 이상
assertSimpleTest(() ->
assertThatThrownBy(() -> runException("//*&\\n1*&2*&3"))
.isInstanceOf(IllegalArgumentException.class)
);
//숫자 사이에 구분자가 아닌 문자
assertSimpleTest(() ->
assertThatThrownBy(() -> runException("//)\\n1*7)3"))
.isInstanceOf(IllegalArgumentException.class)
);
//0(양의 정수만 가능, .는 문자가 될 수 있어 소수 불가능)
assertSimpleTest(() ->
assertThatThrownBy(() -> runException("//#\\n0#30"))
.isInstanceOf(IllegalArgumentException.class)
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반복되는 테스트는 Parameterized Test 등으로 처리할 수 있어요!

}

@Override
Expand Down