Logo

자바스크립트 문자열 자르기: substr()과 substring() 함수

자바스크립트에서 부분 문자열이 필요하실 때 substr()을 쓰시나요 아니면 substring()을 쓰시나요? 혹시 이 두 함수가 동일하다고 생각하시고 계셨나요? 🤪

이름이 비슷한 이 두 함수는 둘 다 문자열의 일부를 잘라내는 기능을 수행하지만 사용 방법과 동작 방식에서 미묘한 차이가 있는데요. 의외로 많은 개발자들이 이 두 함수를 무분별하게 혼용해서 사용하다가 당혹스러운 상황을 겪기도 합니다.

이번 글에서는 substr()substring() 함수에 대해 자세히 알아보고 각각의 특징과 어떤 점이 같고 어떤 점이 다른지에 대해서 살펴보겠습니다.

substr() 함수

먼저 살펴볼 substr() 함수는 문자열의 일부를 일정 길이만큼 추출하고 싶을 때 사용합니다.

다음과 같은 형태로 첫 번째 인자로 시작 인덱스를 두 번째 인자로 잘라낼 길이를 넘기면 됩니다.

"문자열".substr(startIndex, length);

예를 들어, 문자열 "ABCDEFG"를 상대로 23을 인수로 호출하면 "CDE"가 반환되는데요. 자바스크립트에서 인덱스는 0부터 시작하니까 3번째 문자인 C부터 시작해서 총 3글자가 추출되는 것을 볼 수 있습니다.

"ABCDEFG".substr(2, 3); // "CDE"

substr() 함수를 호출할 때 두 번째 인자를 생략하면 첫 번째 인자로 넘긴 시작 인덱스부터 문자열의 끝까지 추출이 됩니다.

"ABCDEFG".substr(2); // "CDEFG"

아무 인자도 넘기지 않으면 문자열이 그대로 얻어지는데 굳이 이렇게 쓰실 일은 없을 것 같습니다.

"ABCDEFG".substr(); // "ABCDEFG"

참고로 첫 번째 인자로 음수 인덱스를 넘길 수도 있는데요. -1이 끝에서 첫 번째 문자이고, -2가 끝에서 두 번째 문자가, -n이 끝에서 n 번째 문자가 됩니다.

"ABCDEFG".substr(-5, 3); //  "CDE"

사실 substr() 함수가 음수 인덱스를 지원하는 부분은 개발자 사이에서도 호불호가 갈리곤 하는데요. 이 기능이 편리하다고 느끼시는 분들도 있고 버그의 원인이 된다고 생각하시는 분들도 있는 것 같습니다.

substring() 함수

다음으로 살펴볼 substring() 함수는 문자열을 시작과 종료 인덱스를 기준으로 자르고 싶을 때 사용하는데요. 두 번째 인자로 문자열 길이 대신에 종료 인덱스를 받는다는 점에서 위에서 살펴본 substr()와 큰 차이가 있습니다.

다음과 같은 형태로 substring() 함수는 첫 번째 인자로 시작 인덱스를 두 번째 인자로 종료 인덱스를 받는데요. 여기서 시작 인덱스만 결과 부분 문자열에 포함되고 종료 인덱스는 부분 문자열에서 제외됩니다.

"문자열".substring(startIndex, endIndex);

예를 들어, 문자열 "ABCDEFG"를 상대로 25을 인수로 호출하면 "CDE"가 반환되는데요. 자바스크립트에서 인덱스는 0부터 시작하니까 3번째 문자인 C부터 시작해서 6번째 문자인 F 바로 전까지 부분 문자열이 얻어 집니다.

"ABCDEFG".substring(2, 5); // "CDE"

substring() 함수를 호출할 때 두 번째 인자를 생략하면 첫 번째 인자로 넘긴 시작 인덱스부터 문자열의 끝까지 추출이 되는데요. 이렇게 첫 번째 인자만 넘기면 substr()와 동일하게 작동하기 때문에 햇갈리게 하는데 주요 원인이 되기도 합니다.

"ABCDEFG".substring(2); // "CDEFG"

substr()과 마찬가지로 아무 인자도 넘기지 않으면 문자열이 그대로 얻어집니다.

"ABCDEFG".substring(); // "ABCDEFG"

substr()과 달리 첫 번째 인자로 음수 인덱스를 넘기면 0을 넘긴 것처럼 작동하는데요. 조심하시지 않으면 버그의 원인이 될 수도 있으므로 주의가 필요하겠습니다.

"ABCDEFG".substring(-5, 3); //  "ABC"

substr() vs. substring()

시작 인덱스와 길이를 기준으로 자르는 substr()와 시작과 종료 인덱스를 기준으로 자르는 substring()는 비슷한 목적을 가지고 있지만 지금까지 살펴본 것처럼 사용 방법과 동작 방식에서 차이가 있어서 주의가 필요합니다.

그런데 여기서 중요한 사실이 하나 있는데요. 바로 substr() 함수는 자바스크립트에서 deprecated, 즉 폐기된 함수입니다. MDN 관련 레퍼런스를 보시면 이제 쓰지 말라고 빨간색 글씨로 경고하고 있습니다.

하지만 아직 많은 개발자 분들이 모르고 사용하고 계시며 과거에 substr()을 사용하여 작성된 레거시 코드가 많기 때문에 substring()과의 차이점에 대해서 인지하고 계시면 도움이 될 것입니다.

다행히도 대부분의 경우, substr()를 써서 작성된 코드는 다음과 같은 간단한 규칙을 통해 substring()을 쓰도록 변환할 수 있습니다.

"문자열".substr(startIndex, length);
"문자열".substring(startIndex, startIndex + length);

예를 들어서 다음 두 줄의 코드는 동일한 부분 문자열을 반환합니다.

"ABCDEFG".substr(2, 3); // "CDE"
"ABCDEFG".substring(2, 2 + 3); // "CDE"

그래서 첫 번째 인자가 0인 경우에는, 두 번째 인자로 무엇을 넘기든 substr()substring()은 항상 동일한 문자열을 반환하게 되죠.

"ABCDEFG".substr(0, 5); // "ABCDE"
"ABCDEFG".substring(0, 0 + 5); // "ABCDE"

이러한 요령을 사용하셔서 가급적 substr()를 사용한 코드를 substring()을 쓰도록 리팩토링(refactoring)하시기를 추천드립니다. Deprecated된 함수를 사용해서 좋을 일은 없으니까요.

보너스: slice() 함수

substr()substring() 만큼 햇갈리는 것은 아니지만 유사한 목적으로 사용되는 함수가 하나 더 있어서 짚고 넘어가려고 합니다. 바로 배열 뿐만 아니라 문자열을 상대로도 사용할 수 있는 slice() 함수인데요.

자바스크립트 배열을 상대로 slice() 함수를 어떻게 사용하는지에 대해서는 관련 포스팅를 참고바랍니다.

이 함수는 첫 번째 인자로 음수 인덱스를 지원한다는 점에서는 substr()과 유사하지만, 두 번째 인자로 종료 인덱스를 받는다는 점에서는 substring()과 유사합니다.

따라서 다음과 같이 지금까지 다룬 모든 함수에 첫 번째 인자를 음수 인덱스를 넘겼을 때 참으로 다채로운 결과를 얻을 수가 있는데요. 이쯤 되면 정말 욕이 나오시죠? 🤬 ㅋㅋㅋ

"ABCDEFG".substr(-5, 3); //  "CDE"
"ABCDEFG".substring(-5, 3); //  "ABC"
"ABCDEFG".slice(-5, 3); // "C"

자, 정신을 차리시고 곰곰이 생각해보면 첫 번째 인수인 -5substring() 함수에서는 0으로 취급되어 "A"가 되지만 slice() 함수에서는 끝에서 5번째 문자인 "C"가 됩니다. 그리고 두 번째 인수인 3은 종료 인덱스이므로 "D"가 되고 그 바로 앞에 있는 문자인 "C"까지만 포함되겠죠? 따라서 우리는 결과로 딱 "C"만 얻게 되는 것입니다.

마치면서

지금까지 미묘하게 비슷하면서도 다른 substr() 함수와 substring() 함수, 그리고 추가로 slice() 함수에 대해서도 살펴보았습니다. 본 포스팅이 이 세 함수를 햇갈려하시는 분들께 도움이 되었으면 좋겠고요. 팀 프로젝트에서 이러한 미묘한 차이에 대해서 걱정하지 않고 코딩할 수 있도록, 가급적 Deprecated된 substr() 함수를 사용을 피하시면 다른 개발자들에게 도움이 될 것입니다.