자바스크립트 문자열 자르기: substr()과 substring() 함수
자바스크립트에서 부분 문자열이 필요하실 때 substr()
을 쓰시나요 아니면 substring()
을 쓰시나요?
혹시 이 두 함수가 동일하다고 생각하시고 계셨나요? 🤪
이름이 비슷한 이 두 함수는 둘 다 문자열의 일부를 잘라내는 기능을 수행하지만 사용 방법과 동작 방식에서 미묘한 차이가 있는데요. 의외로 많은 개발자들이 이 두 함수를 무분별하게 혼용해서 사용하다가 당혹스러운 상황을 겪기도 합니다.
이번 글에서는 substr()
와 substring()
함수에 대해 자세히 알아보고 각각의 특징과 어떤 점이 같고 어떤 점이 다른지에 대해서 살펴보겠습니다.
substr() 함수
먼저 살펴볼 substr()
함수는 문자열의 일부를 일정 길이만큼 추출하고 싶을 때 사용합니다.
다음과 같은 형태로 첫 번째 인자로 시작 인덱스를 두 번째 인자로 잘라낼 길이를 넘기면 됩니다.
"문자열".substr(startIndex, length);
예를 들어, 문자열 "ABCDEFG"
를 상대로 2
와 3
을 인수로 호출하면 "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"
를 상대로 2
와 5
을 인수로 호출하면 "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"
자, 정신을 차리시고 곰곰이 생각해보면 첫 번째 인수인 -5
는 substring()
함수에서는 0
으로 취급되어 "A"
가 되지만 slice()
함수에서는 끝에서 5번째 문자인 "C"
가 됩니다.
그리고 두 번째 인수인 3
은 종료 인덱스이므로 "D"
가 되고 그 바로 앞에 있는 문자인 "C"
까지만 포함되겠죠?
따라서 우리는 결과로 딱 "C"
만 얻게 되는 것입니다.
마치면서
지금까지 미묘하게 비슷하면서도 다른 substr()
함수와 substring()
함수, 그리고 추가로 slice()
함수에 대해서도 살펴보았습니다.
본 포스팅이 이 세 함수를 햇갈려하시는 분들께 도움이 되었으면 좋겠고요.
팀 프로젝트에서 이러한 미묘한 차이에 대해서 걱정하지 않고 코딩할 수 있도록, 가급적 Deprecated된 substr()
함수를 사용을 피하시면 다른 개발자들에게 도움이 될 것입니다.