문자열 배열을 다루다 보면 각 문자열 안에 하나 이상의 숫자가 섞여 있는 경우가 있습니다. 예를 들어 다음과 같은 배열이 있다고 가정해 보겠습니다.
const arr = ['di5aster', 'ca1amity', 'cod3', 'ho2me3', 'ca11ing'];
이때 각 문자열에 포함된 숫자를 추출하여, 그 숫자를 기준으로 배열을 오름차순으로 정렬해야 하는 요구사항이 생길 수 있습니다. 위 배열의 경우 올바른 정렬 결과는 다음과 같습니다.
const output = [ 'ca1amity', 'cod3', 'di5aster', 'ca11ing', 'ho2me3' ];
해결 접근 방식
이 문제는 크게 두 단계로 나누어 해결할 수 있습니다.
1단계: 문자열에서 숫자만 추출하는 함수를 만듭니다. 문자열을 한 글자씩 분리한 뒤, 각 문자의 아스키(ASCII) 코드 값이 48('0')부터 57('9') 사이인지 확인하여 숫자 문자만 필터링하고, 이를 다시 합쳐서 숫자로 변환합니다.
2단계: Array.prototype.sort() 메서드의 비교 함수(comparator)에서 앞서 만든 추출 함수를 활용해 두 문자열의 숫자 값을 비교합니다. 비교 함수가 음수를 반환하면 a가 b보다 앞에 위치하고, 양수를 반환하면 b가 a보다 앞에 위치하게 됩니다.
예제 코드
const arr = ['di5aster', 'ca1amity', 'cod3', 'ho2me3', 'ca11ing'];
// 문자열에서 숫자만 추출하는 함수
const filterNumber = str => {
return +str
.split("")
.filter(el => el.charCodeAt() >= 48 && el.charCodeAt() <= 57)
.join("");
};
// 숫자 값을 비교하는 정렬 함수
const sorter = (a, b) => {
return filterNumber(a) - filterNumber(b);
};
arr.sort(sorter);
console.log(arr);코드 설명
- split(""): 문자열을 개별 문자로 이루어진 배열로 분리합니다.
- filter(): charCodeAt() 메서드로 각 문자의 유니코드 값을 확인하여, 숫자(0~9)에 해당하는 문자만 남깁니다.
- join(""): 필터링된 숫자 문자들을 다시 하나의 문자열로 합칩니다.
- 단항 연산자(+): 문자열을 숫자 타입으로 변환합니다. 예를 들어 '11'은 숫자 11이 됩니다.
이 방식의 장점은 문자열 내 숫자가 여러 자리 연속으로 있어도 올바르게 처리된다는 점입니다. 예를 들어 'ca11ing'의 경우 '1'과 '1'이 연속되어 있으므로 11로 인식됩니다.
실행 결과
위 코드를 실행하면 콘솔에 다음과 같이 출력됩니다.
[ 'ca1amity', 'cod3', 'di5aster', 'ca11ing', 'ho2me3' ]
각 문자열의 숫자가 각각 1, 3, 5, 11, 23이므로 오름차순으로 정확히 정렬된 것을 확인할 수 있습니다.
정규표현식을 활용한 대안
아스키 코드 대신 정규표현식을 사용하면 코드를 더 간결하게 작성할 수도 있습니다.
const filterNumber = str => {
const match = str.match(/\d+/);
return match ? +match[0] : 0;
};이 방법은 연속된 숫자를 한 번에 추출하므로 더 직관적이며, 숫자가 없는 문자열에 대해서도 기본값 0을 반환하도록 처리할 수 있다는 장점이 있습니다.