39. [Java] 세 개의 구분자 - 정규식
https://school.programmers.co.kr/learn/courses/30/lessons/181862
- 임의의 문자열이 주어졌을 때 문자 "a", "b", "c"를 구분자로 사용해 문자열을 나누고자 한다.
- 예를 들어 주어진 문자열이 "baconlettucetomato"라면 나눠진 문자열 목록은 ["onlettu", "etom", "to"]
- 문자열 myStr이 주어졌을 때 위 예시와 같이 "a", "b", "c"를 사용해 나눠진 문자열을 순서대로 저장한 배열을 return
- 단, 두 구분자 사이에 다른 문자가 없을 경우에는 아무것도 저장하지 않으며,
- return할 배열이 빈 배열이라면 ["EMPTY"]를 return
- 1 ≤ myStr의 길이 ≤ 1,000,000
- myStr은 알파벳 소문자로 이루어진 문자열
정답코드
import java.util.*;
class Solution {
public String[] solution(String myStr) {
// 정규표현식 a,b,c 기준으로 분리
String[] splited = myStr.split("[abc]");
// 빈 문자열 제거하기
List<String> list = new ArrayList<>();
for (String s : splited) {
if (!s.isEmpty()) {
list.add(s);
}
}
// 결과 비어있는 경우 return "EMPTY"
if (list.isEmpty()) {
return new String[]{"EMPTY"};
}
return list.toArray(new String[0]);
}
}
✅ String[] splited = myStr.split("[abc]");
split(String regex)
는 정규 표현식(Regex)을 기준으로 문자열을 나누어 문자열 배열로 반환한다."[abc]"
는 정규식에서 'a' 또는 'b' 또는 'c' 중 하나를 의미한다.- 따라서 이 코드는
split()
메서드로 문자열myStr
을 'a', 'b', 'c' 중 하나라도 등장하면 그 위치에서 문자열을 분리한다.
split()
이후 빈 문자열을 제거하는 이유
자바의 split()
메서드는 지정한 구분자 기준으로 문자열을 나눌 때, 구분자 자체는 결과 배열에 포함되지 않는다. 이 문제에서 split("[abc]")
은 "a", "b", "c"를 기준으로 나누지만, 연속되거나 앞뒤에 아무것도 없을 경우 빈 문자열이 생긴다. 그래서 isEmpty()
체크로 실제 값이 있는 문자열만 리스트에 저장해야 우리가 원하는 결과가 나온다.
예를 들어 다음과 같은 문자열이 있을 때:
String myStr = "baconlettucetomato";
→ split 결과: ["", "onlettu", "", "etom", "", "to", ""]
→ 빈 문자열 제거: ["onlettu", "etom", "to"]
→ 최종 반환
String myStr = "abcabc";
→ split 결과: ["", "", "", "", "", "", ""]
→ 빈 문자열 제거 → []
→ ["EMPTY"] 리턴
이처럼 "a"
, "b"
, "c"
는 구분자로 잘렸고, a와 b 사이처럼 아무 문자도 없는 경우에는 빈 문자열("")이 결과에 포함된다. 따라서 우리가 원하는 실제 유효한 문자열만 추출하려면, split()
이후 빈 문자열을 필터링해서 제거해주는 작업이 꼭 필요하다.
for (String s : splited) {
if (!s.isEmpty()) {
list.add(s);
}
}
Stream 으로 푼 코드 (프로그래머스 장홍범 님 외 3인의 코드)
import java.util.Arrays;
class Solution {
public String[] solution(String myStr) {
String[] arr = Arrays.stream(myStr.split("[abc]+"))
.filter(str -> !str.isEmpty())
.toArray(String[]::new);
return arr.length == 0 ? new String[] { "EMPTY" } : arr;
}
}
myStr.split("[abc]+")
'a'
,'b'
,'c'
중 하나 이상(+
)이 등장하는 부분을 기준으로 문자열을 분리한다.- 예:
"abcbaconcabc"
→["", "", "on", "", "on"]
+
때문에 연속된 구분자에도 대응 가능하다
Arrays.stream(...)
- 배열을 스트림으로 변환
.filter(str -> !str.isEmpty())
- 빈 문자열 제거
.toArray(String[]::new)
- 최종적으로 필터링된 값을 다시
String[]
배열로 변환
- 최종적으로 필터링된 값을 다시
정답코드보다 더 간단한 코드 (프로그래머스 김가영님 코드)
import java.util.Arrays;
class Solution {
public String[] solution(String myStr) {
myStr = myStr.replaceAll("[a|b|c]+", ",");
myStr = myStr.charAt(0) == ',' ? myStr.substring(1) : myStr;
myStr = myStr.equals("") ? "EMPTY" : myStr;
return myStr.split("[,]");
}
}
myStr = myStr.replaceAll("[a|b|c]+", ",");
"a"
,"b"
,"c"
중 하나 이상 연속된 구간을 콤마(,)로 치환한다.- 예:
"abcbaconcabc"
→",onlettu,tomato,"
myStr = myStr.charAt(0) == ',' ? myStr.substring(1) : myStr;
- 문자열이 콤마로 시작하는 경우 첫 글자를 잘라낸다.
myStr = myStr.equals("") ? "EMPTY" : myStr;
- 문자열 전체가
"a"
,"b"
,"c"
만으로 구성되어 있었다면 치환 후 빈 문자열이 되는데 이 때"EMPTY"
문자열을 반환한다.
return myStr.split("[,]");
- 최종적으로 콤마를 기준으로 분리하여 배열로 반환한다.
참고 자료 : 프로그래머스 좋아요 가장 많이 받은 코드