문제 정의
문자열 하나와 임의 개수의 구분자(separator) 문자들을 인수로 받아, 지정된 모든 구분자를 기준으로 문자열을 나눈 배열을 반환하는 JavaScript 함수를 작성해야 합니다.
예를 들어 다음과 같은 문자열이 있다고 가정해 보겠습니다.
const str = 'rttt.trt/trfd/trtr,tr';
구분자가 슬래시(/), 마침표(.), 콤마(,)라면,
const sep = ['/', '.', ','];
함수는 다음과 같은 배열을 반환해야 합니다.
const output = [ 'rttt', 'trt', 'trfd', 'trtr', 'tr' ];
방법 1: 반복문과 substring 활용
문자열을 한 글자씩 순회하면서 구분자를 만날 때마다 그 사이의 부분 문자열을 잘라내어 결과 배열에 담는 방식입니다.
const str = 'rttt.trt/trfd/trtr,tr';
const splitMultiple = (str, ...separators) => {
const res = [];
let start = 0;
for(let i = 0; i < str.length; i++){
// 현재 문자가 구분자가 아니면 건너뜀
if(!separators.includes(str[i])){
continue;
}
// 구분자를 만나면 이전 구분자 이후부터 현재 위치까지의 문자열을 저장
res.push(str.substring(start, i));
start = i + 1;
}
// 마지막 구분자 이후 남은 문자열도 누락되지 않도록 처리
if(start < str.length){
res.push(str.substring(start));
}
return res;
};
console.log(splitMultiple(str, '/', '.', ','));
출력 결과
[ 'rttt', 'trt', 'trfd', 'trtr', 'tr' ]
코드 동작 원리
- 가변 인자(...separators) : 전개 연산자(...)를 사용해 구분자를 몇 개든 유연하게 전달할 수 있습니다.
- start 변수 : 현재 부분 문자열이 시작되는 인덱스를 추적합니다.
- substring(start, i) : 구분자를 만난 시점에 start부터 구분자 직전까지의 문자열을 추출해 배열에 추가합니다.
- 마지막 세그먼트 처리 : 문자열 끝에 구분자가 없는 경우 마지막 부분 문자열이 빠지지 않도록 반복 종료 후 한 번 더 확인합니다.
방법 2: 정규 표현식 활용 (더 간단한 방법)
사실 String.prototype.split() 메서드는 정규 표현식을 지원하기 때문에, 위 로직을 한 줄로 대체할 수 있습니다.
const str = 'rttt.trt/trfd/trtr,tr';
const output = str.split(/[\/. ]/);
console.log(output);
출력 결과
[ 'rttt', 'trt', 'trfd', 'trtr', 'tr' ]
정규 표현식 /[\/. ]/는 슬래시, 마침표, 콤마 중 하나와 일치하는 문자를 모두 구분자로 취급합니다. 문자 클래스([]) 안에서는 마침표(.)가 특별한 의미를 갖지 않지만, 슬래시(/)는 정규식 리터럴의 경계와 충돌할 수 있으므로 \/처럼 이스케이프하는 것이 안전합니다.
정리
여러 구분자로 문자열을 나눌 때는 정규 표현식과 split()을 조합하는 방식이 가장 간결하고 실무에서도 널리 사용됩니다. 만약 구분자 목록이 런타임에 동적으로 결정된다면 new RegExp() 생성자로 패턴을 조합하거나, 위에서 소개한 반복문 기반 구현을 활용하면 됩니다.