콤마(,)를 기준으로 사람이름을 구분하려고 한다.
이 때 String에 정의되어있는 split 메소드를 사용하면 다음과 같이 사용할 수 있다.
public void split() {
String names = "주노, 누누, 필립, 폴로";
String[] split = names.split(",");
...
}
그런데 split 함수는 limit라는 인자도 가질 수 있다..?!
위와 같은 입력이 이뤄졌을 때 뒤에 오는 ,,
라는 문자로 인해 잘못된 입력이라는 결과를 기대할 수 있다.
하지만 위 입력을 처리하는 로직은 다음과 같이 구성되어있다.
public List<String> readParticipantName() {
System.out.println("게임에 참여할 사람의 이름을 입력하세요.(쉼표 기준으로 분리)");
final String input = scanner.nextLine();
return splitByComma(input);
}
private List<String> splitByComma(final String input) {
return List.of(input.split(","));
}
입력이 정상적으로 수행된다..? 왜 이런일이 일어날까?
String.split 메소드가 limit 인자를 받으면서 해당 문제를 어떻게 해결할 수 있을 지 알아보자
String 클래스에 정의되어있는 메소드를 살펴보면 다음과 같이 작성되어있다.
public String[] split(String regex, int limit) {
/* fastpath if the regex is a
(1)one-char String and this character is not one of the
RegEx's meta characters ".$|()[{^?*+\\", or
(2)two-char String and the first char is the backslash and
the second is not the ascii digit or ascii letter.
*/
char ch = 0;
if (((regex.length() == 1 &&
".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
(regex.length() == 2 &&
regex.charAt(0) == '\\' &&
(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
((ch-'a')|('z'-ch)) < 0 &&
((ch-'A')|('Z'-ch)) < 0)) &&
(ch < Character.MIN_HIGH_SURROGATE ||
ch > Character.MAX_LOW_SURROGATE))
{
int off = 0;
int next = 0;
boolean limited = limit > 0;
ArrayList<String> list = new ArrayList<>();
while ((next = indexOf(ch, off)) != -1) {
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
} else { // last one
//assert (list.size() == limit - 1);
int last = length();
list.add(substring(off, last));
off = last;
break;
}
}
// If no match was found, return this
if (off == 0)
return new String[]{this};
// Add remaining segment
if (!limited || list.size() < limit)
list.add(substring(off, length()));
// Construct result
int resultSize = list.size();
if (limit == 0) {
while (resultSize > 0 && list.get(resultSize - 1).isEmpty()) {
resultSize--;
}
}
String[] result = new String[resultSize];
return list.subList(0, resultSize).toArray(result);
}
return Pattern.compile(regex).split(this, limit);
}
대충 읽어봐서는 무슨소린지 잘 모르겠으니 3줄 요약을 해보자.
크게 limit인자에 대해 3가지의 경우로 나뉜다.
limit가 0보다 클 경우 limit 개수만큼 split을 진행한다.
@Test
void splitTest() {
String names = "주노-누누-폴로-----";
String[] split = names.split("-", 2);
System.out.println(Arrays.toString(split));
}
결과는 다음과 같다.
[주노, 누누-폴로-----]
limit가 0일 경우 맨 뒤의 값이 빈값이면 생략한다.
split(",")
처럼 limit인자가 주어지지 않으면 기본적으로 limit = 0인 상태로 split 메소드가 동작한다.
@Test
void splitTest() {
String names = "주노-누누-폴로-----";
String[] split = names.split("-", 0);
System.out.println(Arrays.toString(split));
}
결과는 다음과 같다.
[주노, 누누, 폴로]
limit가 0보다 작을 경우 맨 뒤의 빈값에 대해 split을 모두 진행한다.
어떤 의미인지 한번 알아보자.
@Test
void splitTest() {
String names = "주노-누누-폴로-----";
String[] split = names.split("-", -1);
System.out.println(Arrays.toString(split));
}
결과는 다음과 같다.
[주노, 누누, 폴로, , , , , ]
끝의 비어있는 값에 대해서도 split을 진행하는 것을 알 수 있다.
위 문제상황에서 겪었던 잘못된 입력에 대해 정상적인 validation 과정을 거치기 위해서는 -1 옵션을 추가해주는 방향으로 진행해볼 수 있겠다. 👍