먹고 기도하고 코딩하라

자바스크립트 String 메소드 결과 간단 실험 본문

Javascript

자바스크립트 String 메소드 결과 간단 실험

사과먹는사람 2020. 6. 17. 18:35
728x90
728x90

 

자바스크립트의 String 메소드는 매번 적어놓고 보는데도 잘 안 외워집니다. 사이드 이펙트가 있는지도 까먹고 해서 이 참에 정리해보고자 간단 실험을 해봤습니다.

 


 

String Method

일단 String 객체는 immutable한 객체이기 때문에 String 객체 레퍼런스에 무슨 메소드를 실행해도 원본 문자열이 변경되진 않는다는 사실을 짚고 갑니다. String에서는 메소드의 반환형이 어떤지만 살펴보겠습니다.

 

let str = 'Beam me up, Scotty!';
console.log(str.split(''));	//["B", "e", "a", "m", " ", "m", "e", ... "y", "!"]
console.log(str.split(' '));	//["Beam", "me", "up,", "Scotty!"]
console.log(str.split('z'));	//["Beam me up, Scotty!"]
console.log(`after str.split: ${str}`);	//Beam me up, Scotty!

str.split(token: String)의 반환 타입은 Array입니다. token을 기준으로 문자열을 나눠 그것을 Array에 담아 반환합니다.

토큰으로 공백도 아닌 것을 주면 그냥 한 글자 단위로 끊어서 배열로 담고, 화이트 스페이스나 문자처럼 의미있는 것을 토큰으로 주면 그것을 기준으로 문자열이 나뉩니다. 이 때 토큰은 어느 요소에도 들어가지 않는 separator 역할을 합니다. 이것을 잘 이용하면 밑에 보게 될 replace의 확장판을 만들 수 있습니다.

만약 없는 문자(예를 들어 'z')를 기준으로 split을 하게 되면 원본 문자열 그대로 배열에 들어가게 됩니다.

 

 

검색 메소드

문자열에서 어떤 문자가 있는지 검색하고 확인하는 메소드 몇 가지를 살펴보겠습니다.

 

 console.log(str.indexOf('m'));	//3
 console.log(`after str.indexOf: ${str}`);	//Beam me up, Scotty!
 console.log(str.lastIndexOf('m'));	//5
 console.log(str.lastIndexOf('z'));	//-1
 console.log(`after str.lastIndexOf: ${str}`);	//Beam me up, Scotty!

str.indexOf(String), str.lastIndexOf(String)의 반환 타입은 int입니다.

str.indexOf('m')을 하게 되면 문자열의 부터 조사해서 처음으로 'm'이 나오는 인덱스를 반환하게 됩니다. 

str.lastIndexOf('m')을 하게 되면 문자열의 부터 조사해서 처음으로 'm'이 나오는 인덱스를 반환하게 됩니다. 즉, 문자열 전체에서 'm'이 마지막으로 나오는 인덱스를 반환합니다.

indexOf와 lastIndexOf 메소드 모두 없는 문자나 문자열을 매개변수로 줘서 실행하면 -1을 반환합니다.

 

console.log(str.search('y'));	//17
console.log(str.search('e'));	//-1
console.log(`after str.search: ${str}`);	//Beam me up, Scotty!
console.log(str.match('e'));	//["e", index: 1, input: "Beam me up, Scotty!", groups: undefined]
console.log(str.match('z'));	//null
console.log(`after str.match: ${str}`);	//Beam me up, Scotty!

search와 match는 정규식을 매개변수로 갖지만, 일반 문자를 가질 수도 있습니다. 

str.search(String)의 반환 타입은 int입니다. str.search('y')를 하게 되면 indexOf 메소드처럼 문자열의 부터 조사해서 'y'가 처음으로 나오는 인덱스를 반환하게 됩니다. 정규식을 쓸 수 있다는 것이 indexOf와의 차이점입니다. 찾는 문자가 문자열에 없다면 -1을 반환합니다.

str.match(String)의 반환 타입은 Array입니다. str.match('e')를 해서 문자열 내 'e'를 찾는다면 'e'를 첫 번째 원소로 갖는 배열을 반환하게 됩니다. 이 때 찾은 인덱스(맨 처음 나온 인덱스), 검색한 원본 문자열의 정보도 함께 담깁니다. 만약 'z'처럼 없는 문자를 찾게 되면 null을 반환합니다.

 

  indexOf lastIndexOf search match
반환형 int (최초 인덱스) int (마지막 인덱스) int (최초 인덱스) Array
검색 실패 시 반환 -1 -1 -1 null
정규식 사용 여부 X O

 

 

슬라이싱 메소드

문자열에서 원하는 부분을 자른 문자열을 가져오는 메소드들을 살펴보겠습니다.

 

let n = 5;

console.log(str.slice(3, 3));	//''(공백)
console.log(str.slice(3, 7));	//m me 
console.log(str.slice(8, 5));	//''(공백)
console.log(str.slice(10, -5));	//, Sc
console.log(str.slice(-5, 3));	//''(공백)
console.log(str.slice(-5, -8));	//''(공백)
console.log(str.slice(-5, -3));	//ot
console.log(str.slice(10));	//, Scotty!
console.log(str.slice(-5));	//otty!

console.log(str.substring(3, 7));	//m me 
console.log(str.substring(8, 5));	//me 
console.log(str.substring(10, -5));	//Beam me up
console.log(str.substring(10));	//, Scotty!
console.log(str.substring(-5));	//Beam me up, Scotty!
console.log(str.substring());	//Beam me up, Scotty!
console.log(str.substring(n));	//me up, Scotty!

console.log(str.substr(3, 3));	//m m
console.log(str.substr(3, 7));	//m me up
console.log(str.substr(10, -5));	//''(공백)
console.log(str.substr(-5, 3));	//ott
console.log(str.substr(-5, -8));	//''(공백)
console.log(str.substr(-5, -3));	//''(공백)
console.log(str.substr(10));	//, Scotty!
console.log(str.substr(-5));	//otty!

console.log(`after str.substr: ${str}`);	//Beam me up, Scotty!

str.slice(start:int, end:int)의 경우 start 인덱스인 3번부터 end-1번째인 6번까지의 4개(7-3개) 문자를 반환합니다.

보시는 바와 같이 str.slice의 경우 음수 인덱스로도 정상 접근이 가능합니다. 참고로 음수 인덱스는 맨 끝인 !이 -1, 그 앞의 y가 -2, t는 -3, -4... 이런 식입니다. 쉽게 말해 slice 메소드로 접근할 수 있는 인덱스는 -length~length-1까지입니다. 그리고 -length와 0은 같은 자리를 가리킵니다.

하지만 음수 사용은 제한적인데, 4번째 문장은 첫 번째 인자에 음수가 왔더니 공백이 출력됩니다. 이것은 substr 메소드에서 두 번째 인자에 음수를 넣었을 때 나오는 결과와 같습니다. 또 start가 음수일 때 end가 양수이거나, 음수더라도 더 작은 수라면 공백이 출력됩니다. 조금 까다롭네요.

만약 start와 end 인덱스가 같다면 공백을 반환하게 됩니다. 이것은 substring도 마찬가지입니다. 인자로 반드시 정수 리터럴이 들어갈 필요는 없고, 정수 변수를 사용할 수도 있습니다. 

str.slice(idx)의 경우 idx 인덱스인 10번부터 문자열 끝까지 쭉 반환합니다. 그래서 ', Scotty!'가 결과로 나옵니다.

추가로 slice()와 substring(), substr() 모두 인자를 아무것도 쓰지 않고 비워두게 되면 원본 문자열을 반환하게 됩니다.

 

str.substring(start:int, end:int)의 경우도 str.slice와 마찬가지로 동작합니다. 다만 substring 메소드는 음수 인자를 받아들이지 않고 0으로 치환하게 됩니다. str.substring(10, -5)는 결과적으로는 str.substring(0, 10)과 같게 됩니다. 음수 인덱스 사용 여부가 slice와 substring 간의 차이입니다. 

 

str.substr(start:int, num:int)은 slice와 substring 메소드와는 다소 다르게 동작합니다. slice(3, 7)과 substring(3, 7)의 결과가 3~6번 인덱스의 4개 문자를 가져오는 거였다면 substr(3, 7)은 3번부터 9번까지 총 7개 문자를 가져오게 됩니다. 쉽게 말해 substr(3, 7)은 slice(3, 10), substring(3, 10)과 똑같은 것이지요.

substr의 경우 음수 인덱스 사용을 허용하지만 2개 인자를 줄 때 2번째 인자인 num 값으로 음수를 주면 무조건 공백이 출력됩니다. 이유는 slice와 substring이 end 인덱스 자리까지 문자를 출력하게 되어 있는 반면 substr은 num 인덱스의 수만큼 문자를 출력하기 때문이죠. 음수 개수만큼 출력한다는 건 말이 안 되죠? 그래서 두 번째 인자가 음수면 공백이 출력되는 겁니다. 그 외에 인자가 하나일 때 음수를 주거나 start 자리에 음수를 주는 경우에는 정상적으로 동작합니다. 

slice, substring, substr 메소드 모두 인자의 타입은 int, 반환타입은 String입니다.

 

 

정리해 보겠습니다.

 

Beam me up, Scotty!
  slice substring substr
공통점 인자가 없을 때 전체 문자열 반환 / 정수 변수로 인자 주기 가능
음수 인덱싱 허용 여부 O X (음수를 0으로 만듦) O
인자가 (5)일 때 me up, Scotty!
인자가 (-5)일 때 otty! Beam me up, Scotty! otty!
인자가 (3, 3)일 때 (공백) me up
(3, 7)일 때 출력과 갯수 m me
(4개. 7-3=4)
m me up
(7개. 7)
적절한 용도 start 인덱스부터 end까지만 문자가 필요할 때
음수 인덱싱이 필요한 상황
start 인덱스부터 end까지만 문자가 필요할 때
내 프로그램에서 음수 인덱싱은 명백한 실수다. 0으로 바꿔주면 좋겠다!
start 인덱스부터 일정 갯수만큼 문자가 필요할 때
음수 인덱싱이 필요한 상황

 

좀 더 복잡한 예제를 표로 만들어 보겠습니다.

 

Beam me up, Scotty!
length : 19
인자 slice (start, end) substring (start, end) substr (start, num)
(-5, -3) ot
(14, 16)으로 해석됨
(공백)
(-5,  -8) (공백)
(-5, 3) (공백) Bea
(0, 3)으로 해석됨
ott
(14, 17)으로 해석됨
(5, -3) me up, Scot
(5, 16으로 해석됨)
Beam
(0, 5로 해석됨) 
(공백)
(5, 3) (공백) m
(3, 5)로 해석됨
me 
(5, 8) me  me  me up, S

 

  •  slice
    • start 인자가 음수일 때 결과가 출력되는 케이스는 end 인자가 start보다 크며 음수일 때뿐입니다.
    • start 인자가 양수일 때 end 인자가 start보다 작은 양수라면 결과가 출력되지 않습니다.
    • start 인자가 양수일 때 end 인자가 음수라면 length+(end)로 해석해서 출력됩니다.
  • substring
    • start 인자가 음수일 때 결과가 출력되는 케이스는 end 인자가 1 이상의 양수일 때뿐입니다. (0도 안 됩니다. (-5, 0)일 때는 (0, 0)이나 마찬가지라서 공백입니다.)
    • start 인자가 양수라면 두 인자가 length 내의 숫자라는 조건 아래 어떤 케이스라도 결과물이 일단 출력은 됩니다.
    • start 인자가 양수일 때 end 인자가 음수이거나 start보다 작은 양수라면 start와 end를 뒤집어 (0, start) 혹은 (end, start)로 해석됩니다.
  • substr
    • start 인자가 음수일 때 결과가 출력되는 케이스는 end 인자가 1 이상의 양수일 때뿐입니다. (0도 안 됩니다. (-5, 0)일 때는 -5번 인덱스부터 0개 문자를 가져오는 것이라서 공백입니다.) 이것은 바로 아래 num 인자의 제약 때문입니다.
    • num 인자가 음수라면 그 어떤 경우라도 공백이 나옵니다. substr은 start 인덱스에서 num만큼 문자를 가져오는 것이기 때문에 num은 반드시 1 이상의 양수여야 합니다.

 

console.log(str.toLowerCase());	//beam me up, scotty!
console.log(str.toUpperCase());	//BEAM ME UP, SCOTTY!

str.toLowerCase()str.toUpperCase()는 각각 문자열의 전체를 모조리 소문자나 대문자로 만들어 반환하는 메소드입니다. 인자 타입은 void이며 반환 타입은 String입니다.

 

 

console.log(str.charAt(5));	//m
console.log(str.charCodeAt(5));	//109
console.log(str.charAt(-5));	//(공백)
console.log(str.charCodeAt(-5));	//NaN

str.charAt(n:int)은 문자열의 n번째 인덱스의 문자 한 개를 반환하는 메소드로 반환형은 String(정확히는 Char)입니다. 정수 변수를 인자로 사용해도 괜찮습니다. 단, 음수를 사용할 수 없습니다. 음수를 사용하면 공백이 출력됩니다.

str.charCodeAt(n:int)은 문자열의 n번째 인덱스의 문자 한 개의 아스키 코드를 반환하는 메소드로 반환형은 int(Number)입니다. 이 역시 정수 변수를 인자로 사용해도 괜찮습니다. 단, 음수를 사용할 수 없습니다. 음수를 사용할 경우 NaN이 출력됩니다. 

charAt과 charCodeAt 메소드는 정수 변수를 인자로 사용해도 되며, 음수를 사용할 수 없다는 공통점을 가지고 있습니다.

 

str = '     Beam   m e  u  p ,   S cotty!!!!!       ';
console.log(str.trim());	//Beam   m e  u  p ,   S cotty!!!!!

str.trim() 메소드의 인자 타입은 void, 반환 타입은 String입니다. trim()을 사용하면 문자열 앞뒤의 공백을 모두 없애서 반환해줍니다. 단, 문자열 안의 공백은 의도된 것이라고 생각하고 전혀 신경쓰지 않습니다. 일부러 문자열 안에 공백을 많이 넣어봤습니다만 문자열 내 공백은 멀쩡합니다.

 

str = 'Beam me up, Scotty!';
console.log(str.replace('e', 'i'));	//Biam me up, Scotty!
console.log(str.replace('me', 'Sulu'));	//Beam Sulu up, Scotty!
console.log(`after str.replace: ${str}`);	//Beam me up, Scotty!

str.replace(target:String, want:String)의 반환 타입은 String입니다. replace 메소드를 사용하면 문자열의 앞에서부터 조사해 제일 먼저 찾은 target을 want로 바꿔서 반환합니다. 단 한 개의 문자가 아니라 여러 문자여도 상관없습니다.

단, 제일 먼저 찾은 target만 바꿔주기 때문에 2번 문장을 보면 Beam me up, Scotty! 라는 문장에 e가 두 개 들어있지만 첫 번째 e만 바뀌어서 Biam me up이 됐죠.

전부 다바꾸는 replaceAll을 하고 싶다면 다음과 같이 하면 됩니다.

 

const replaceAll = (str, target, want) => str.split(target).join(want);
console.log(replaceAll(str, 't', 'f');	//Beam me up, Scoffy!

 

String을 token 단위로 끊어 Array에 담아 반환하는 split과 Array의 요소들을 token 단위로 묶어 String으로 반환하는 환상의 콜라보로 replaceAll을 구현할 수 있습니다. ㅎㅎ

 

 

String 메소드는 일단 이 정도로 마치겠습니다. 고맙습니다. ^^

 

 

 

728x90
반응형
Comments