split
string이 주어져 있을 때 내가 원하는 글자를 기준으로 잘라 배열에 저장시키는 기능.
strtok( 문자열의 시작 주소, 찾기 시작할 위치 )
String 함수로써 string 글자에서 원하는 글자를 찾아 시작 위치를 반환받을 수 있습니다.
( Overloading 되어있기 때문에 parameter가 더 있음 )
관련 글
[C++] Split #1 - String delimiter split 함수 구현
이번에는 지난번 글에 이어서 C++에서의 split 기능을 두번째로 구현해보겠습니다. 이번 글에서 구현할 split은 이전 글에서도 언급했지만 다수의 delimiter를 기준으로 String을 나눠주는 기능입니다. 이러한 기능의 split은 얼핏 기억을 떠올려보면 사칙연산의 식이 input으로 들어와 연산 기호를 제외한 각 숫자들을 배열에 넣어줘야할 때 필요했습니다. ( 대표적으로 2020 카카오 인턴쉽 코딩테스트 2번 문제가 있습니다. )
strtok() 함수 기능
우선 이번 글에서 가장 핵심적인 함수인 strtok() 함수를 소개하겠습니다.
strtok( 문자열의 시작 주소, 구분할 delimiter ) String의 함수로써 변수 s가 있다고 가정했을 때 strtok( s, "+-*/" ) 처럼 사용할 수 있다. 이 기능은 변수 s의 첫 문자를 시작으로 문자 '+', '-', '*', '/' 를 찾은 뒤 문자열의 시작 주소를 반환한다. |
strtok() 함수에 대해 좀 더 자세하게 설명하겠습니다. strtok은 찾을 문자열에서 delimiter를 찾았다면 해당 문자를 '\0'으로 변환시키고 분리될 문자열의 시작점을 반환합니다. 즉 argument로 사용한 문자열 변수의 시작점을 반환하는 것이죠. 우리는 반환된 값을 String 변수로 받으면 해당 주소에 저장되어 있는 값을 받을 수 있고, delimiter가 '\0'으로 변환되어 있기 때문에 끝 문자로 인식해 delimiter 이전까지의 분리된 문자열만 결과로 받아올 수 있습니다.
그렇다면 두 번째 delimiter를 기준으로 한번 더 split 하고 싶다면 어떻게 해야할까요? String 변수에서 첫 번째 delimiter 다음 주소를 넣어줘야 할까요? 결론부터 말씀드리면 그럴필요 없습니다! strtok() 함수는 delimiter를 찾으면 그 다음 주소를 내부적인 로직에서 static 변수에 저장해놓습니다. 그래서 사용자 입장에서는 첫 번째 argument 자리에 NULL 값만 넣어주면 저장해놓은 static 변수로부터 위치를 가져와 다시 delimiter를 찾습니다.
split 구현 예시
split을 구현하기 전 원리를 알기 위해 예시를 하나 만들겠습니다. string 변수 S가 "34+2-11*541"라는 값을 가질 때 사칙 연산 기호인 '+', '-', '*', '/'를 delimiter로 삼아 split 기능을 수행한다면 어떤 알고리즘으로 구현될까요? 위에서 strtok()에 대해 알았다면 아래 그림에서 split의 단계적인 과정을 살펴보겠습니다.
strtok() 함수를 통해 사칙연산의 기호는 문자열의 끝 문자인 '\0'으로 변환됩니다. 그와 동시에 반환 값은 문자열의 시작주소이기 때문에 결국 사칙연산의 기호 전까지 문자열을 결과로 받을 수 있는 것이죠.
그리고 위에서 말했듯이 strtok() 함수는 찾은 delimiter의 위치 값을 저장해 놓습니다. 그래서 처음에만 문자열을 argument로 사용하고 이후에는 NULL을 넣습니다.
가장 마지막을 보자면 문자 '5'의 위치가 시작점이고 이후에는 찾은 delimiter가 없기 때문에 변환된 값이 없습니다. 하지만 기본적으로 문자열 자체의 마지막에는 '\0' 문자가 존재하기 때문에 "541" 이라는 문자열을 얻을 수 있었습니다.
마지막 문자열 "541"을 결과로 받은 후 다시 한번 strtok() 함수를 사용하면 어떻게 될까요? 이미 앞의 문자열의 탐색은 끝난 상태기 때문에 더 이상 탐색하려는 문자열 자체가 존재하지 않습니다. 그래서 결국 NULL 값을 반환시키고 우리는 이점을 이용해서 split 기능을 끝낼 수 있습니다.
그렇다면 이번 글에서 설명한 원리의 split 함수 구현 코드를 보도록 합시다. 여기서 주의할 점은 strtok()의 첫번째 parameter는 char* 입니다. 그래서 우리가 보통 C++에서 사용하는 string 변수를 넣을 수 없습니다. 그래서 중간에 string을 char 배열로 바꾸는 과정이 필요합니다.
C++ Code
#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
vector<string> split(string s){
vector<string> sv;
char cs[100];
strcpy(cs,s.c_str());
char* tok = strtok(cs,"-+*/");
while(tok != NULL){
sv.push_back(tok);
tok = strtok(NULL,"-+*/");
}
return sv;
}
int main(int argc, const char * argv[]) {
string s = "34+2-11*541";
vector<string> split_result = split(s);
for(int i=0; i < split_result.size(); i++)
cout << "split element " << i << " : " << split_result[i] << endl;
}
'Computer Science > C++' 카테고리의 다른 글
[C++] Split #1 - String delimiter split 함수 구현 (0) | 2021.01.28 |
---|---|
[C++] 2차원 배열 행렬 바꾸기 (0) | 2021.01.25 |
[C++] 2차원 배열 90도 회전 (2) | 2021.01.23 |
[C++] 2차원 배열 특정 값 초기화 (0) | 2021.01.17 |
[C++] 구조체 생성자 오버로딩 Struct Constructor Overloading (0) | 2021.01.10 |