[Java] 프로그래머스(level-1) - 신규 아이디 추천

입출력 예시
Input-1
“…!@BaT#*..y.abcdefghijklm”
Output-1
“bat.y.abcdefghi”
Input-2
“z-+.^.”
Output-2
“z–“
Input-3
”=.=”
Output-3
“aaa”
Input-4
“abcdefghijklmn.p”
Output-4
“abcdefghijklmn”
문제 풀이
주어진 입력문자열을 단계별로 검증하고 변경해야 한다.
그럼 단계별로 순차적으로 아이디를 검증해보자.
단계별 풀이
1단계 문자열을 순회하며 대문자가 있을 경우 소문자로 변환하여 저장하자.
1
2
3
4
5
char[] new_id_arr = new_id.toCharArray(); // char형 입력문자열
for(int i=0; i<new_id.length(); i++) {
char id = new_id.charAt(i);
if(Character.isUpperCase(id)) new_id_arr[i] = Character.toLowerCase(id);
}
2단계 입력문자열에서 소문자와 숫자, “.”, “-“, “_” 문자만 answer에 담는다.
1
2
3
4
5
String answer = "";
for(int i=0; i<new_id_arr.length; i++) {
char id = new_id_arr[i];
if(('a'<=id && 'z'>=id) || ('0'<=id && '9'>=id) || id=='.' || id=='-' || id=='_') answer += id;
}
3단계 연속된 마침표가 존재할 경우 하나의 마침표로 치환하기 위해 replaceAll() 메서드로 정규표현식을 활용합니다.
1
answer = answer.replaceAll("\\.+", ".");
str.replaceAll(
"\\.+"
, “.”)
정규식"\."
는 마침표를 나타낸다. 그리고 “+”는 1번 이상을 의미합니다.
즉, “\s+”는 1개 이상 존재하는 마침표임을 알 수 있다.
따라서, 위 코드는 연속되는 마침표를 하나의 마침표로 치환할 수 있다.
4단계
문자열의 양쪽 끝에 마침표가 존재할 경우 제거해야 한다.
직접 문자열 배열 내 원소를 제거하는 것보다 substring()을 통한 슬라이싱을 활용하였다.
1
2
3
4
5
6
7
if(answer.length() > 1) {
if(answer.charAt(0)=='.') answer = answer.substring(1, answer.length());
if(answer.charAt(answer.length()-1)=='.') answer = answer.substring(0, answer.length()-1);
}
else if(answer.length() > 0 && answer.length()==1) {
if(answer.charAt(0)=='.') answer = "";
}
5단계 4단계까지 실행 한 문자열이 빈 문자열일 경우 “a” 문자를 대입한다.
1
if(answer.equals("") || answer.isEmpty() || answer==null) answer += "a";
6단계 문자열 길이가 16자 이상일 경우 처음부터 15자 까지만 자른 후 4단계와 동일하게 양쪽 끝 마침표를 제거한다.
1
2
3
4
if(answer.length()>=16) answer = answer.substring(0, 15);
// 4단계 재실행
if(answer.charAt(0)=='.') answer = answer.substring(1, answer.length());
if(answer.charAt(answer.length()-1)=='.') answer = answer.substring(0, answer.length()-1);
동일한 코드기에 4단계를 한 번 더 실행하도록 고치면 좋을 겉 같다.
7단계 6단계까지 실행 한 문자열의 길이가 2자 이하일 경우 3글자가 될때까지 제일 마지막 글자를 반복해서 대입한다.
1
2
3
4
5
if(answer.length()<=2) {
while(answer.length()!=3) {
answer += answer.charAt(answer.length()-1);
}
}
함수형 로직으로 변경
단계별로 풀이한 코드를 보니, 단계별 기능들이 모두 다르거나 같은 기능을 내포하고 있었다.
가독성을 높이기 위해 각 단계별 코드를 함수형으로 분리하여 재작성하였다.
자세한 코드 내용은 아래 작성코드에 첨부하였다.
작성 코드
작성 코드 - 단계별 풀이
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Solution {
public String solution(String new_id) {
String answer = "";
char[] new_id_arr = new_id.toCharArray();
// 1단계
for(int i=0; i<new_id.length(); i++) {
char id = new_id.charAt(i);
if(Character.isUpperCase(id)) new_id_arr[i] = Character.toLowerCase(id);
}
// 2단계
for(int i=0; i<new_id_arr.length; i++) {
char id = new_id_arr[i];
if(('a'<=id && 'z'>=id) || ('0'<=id && '9'>=id) || id=='.' || id=='-' || id=='_') answer += id;
}
// 3단계
answer = answer.replaceAll("\\.+", ".");
// 4단계
if(answer.length() > 1) {
if(answer.charAt(0)=='.') answer = answer.substring(1, answer.length());
if(answer.charAt(answer.length()-1)=='.') answer = answer.substring(0, answer.length()-1);
}
else if(answer.length() > 0 && answer.length()==1) {
if(answer.charAt(0)=='.') answer = "";
}
// 5단계
if(answer.equals("") || answer.isEmpty() || answer==null) answer += "a";
// 6단계
if(answer.length()>=16) answer = answer.substring(0, 15);
if(answer.charAt(0)=='.') answer = answer.substring(1, answer.length());
if(answer.charAt(answer.length()-1)=='.') answer = answer.substring(0, answer.length()-1);
// 7단계
if(answer.length()<=2) {
while(answer.length()!=3) {
answer += answer.charAt(answer.length()-1);
}
}
return answer;
}
}
작성코드 - 함수형 풀이
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Solution {
public String solution(String new_id) {
String answer = "";
char[] new_id_arr = step1(new_id);
answer = step2(new_id_arr);
answer = step3(answer);
answer = step4(answer);
answer = step5(answer);
answer = step6(answer);
answer = step7(answer);
return answer;
}
private static char[] step1(String new_id) {
char[] new_id_arr = new_id.toCharArray();
for(int i=0; i<new_id.length(); i++) {
char id = new_id.charAt(i);
if(Character.isUpperCase(id)) new_id_arr[i] = Character.toLowerCase(id);
}
return new_id_arr;
}
private static String step2(char[] new_id_arr) {
String answer = "";
for(int i=0; i<new_id_arr.length; i++) {
char id = new_id_arr[i];
if(('a'<=id && 'z'>=id) || ('0'<=id && '9'>=id) || id=='.' || id=='-' || id=='_') answer += id;
}
return answer;
}
private static String step3(String answer) {
return answer.replaceAll("\\.+", ".");
}
private static String step4(String answer) {
if(answer.length() > 1) {
if(answer.charAt(0)=='.') answer = answer.substring(1, answer.length());
if(answer.charAt(answer.length()-1)=='.') answer = answer.substring(0, answer.length()-1);
}
else if(answer.length() > 0 && answer.length()==1) {
if(answer.charAt(0)=='.') answer = "";
}
return answer;
}
private static String step5(String answer) {
if(answer.equals("") || answer.isEmpty() || answer==null) answer += "a";
return answer;
}
private static String step6(String answer) {
if(answer.length()>=16) answer = answer.substring(0, 15);
answer = step4(answer);
return answer;
}
private static String step7(String answer) {
if(answer.length()<=2) {
while(answer.length()!=3) {
answer += answer.charAt(answer.length()-1);
}
}
return answer;
}
}
회고
- 모듈 내에서 여러 기능들을 어떻게 분리할 것이고, 공통사항은 어떻게 합칠 것인지 고민하는 과정이 단순히 알고리즘 공부를 넘어 자바를 자바답게 활용하는 데 큰 도움이 될 것이라고 느꼈다.
- replaceAll() 메서드에서 활용할 자주 쓰이는 정규표현식들을 공부해야겠다.