본문 바로가기
알고리즘 문제풀이

[C++] C++에서 문자열 split하기 (istringstream, getline)

by SiO2whocode 2021. 10. 6.
728x90

istringstream과 getline사용

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main(){
    //나눌 문자열
    string str = "C is quirky, flawed, and an enormous success";
    //나눈 문자열들을 담을 변수
    string token;
 
    //방법1 : istringstream 사용

    //문자열을 ' '(공백 1칸)으로 구분하기
    istringstream iss(str); //str을 입력받은 input string stream
    
    //getline은 구분자로 char 즉 하나의 문자 밖에 못받음
    while(getline(iss, token, ' '))
        cout << token << "\n";
        
    //같은 문자열을 ,로 구분하기
    //stream을 흔히 흐르는 물에 비유하듯이 한번 흘려보내면 끝. 재사용 불가.
    //같은 문자열도 다시 쓰려면 또 다른 stream을 선언해줘야한다.
    istringstream iss2(str);
    while(getline(iss2, token, ','))
        cout << token << "\n";
        
    return 0;
}​

우리가 사용하는 getline함수는 <string> 라이브러리를 include해줘야 한다.
하지만 getline함수를 사용하기 위해서 istringstream을 매개변수로 사용해야 하므로
istringstream을 생성하기 위해 <sstream> (input, output string stream) 라이브러리를 include해줘야 한다.

//구분자(delimitation character)를 만날 때 까지 문자열을 입력 받아 하나의 string 객체(str)에 저장
istream& getline(istream& s, string& str, char delim);

https://www.cplusplus.com/reference/string/string/getline/

 

getline (string) - C++ Reference

function <string> std::getline (string) (1)istream& getline (istream& is, string& str, char delim); (2)istream& getline (istream& is, string& str); (1)istream& getline (istream& is, string& str, char delim); istream& getline (istream&& is, string& str, cha

www.cplusplus.com

여기서 사용되는 getline 함수는 istream으로부터 문자열을 추출해서 str에 저장하는 함수이다.
istream에서 문자열을 추출할 때, delimiter(구분자)가 나올 때 까지 추출하거나, 아니면 파일의 끝에 다다르면 추출을 끝낸다.
getline함수를 사용할 때 인자로 delimiter을 전달하지 않으면 '\n'(줄바꿈)을 발견하거나 파일의 끝에 다다르면 추출을 끝낸다.
또한 입력 과정에서 어떠한 오류가 발생해도 추출을 종료한다.


delimiter는 char 타입이므로 한자리의 문자만 대입될 수 있다. -> 두 자리 이상의 문자열로 구분하는 것은 불가능


istream에서 문자열을 추출하여 str에 저장할 때
str에 무슨 값이 담겨있든지 상관하지 않고 지금 추출한 문자열로 덮어쓴다.

getline함수가 반환하는 값은 매개변수로 받은 istream을 그대로 반환한다.
또는 the internal state flags of istream 즉, istream의 내부 상태 플래그를 반환하기도 하는데
flag의 종류로는 eofbit, failbit, badbit 가 있다.

우리가 while문 조건에 getline함수를 작성하면,
istream이 반환되거나 flag들이 반환되는데
1) istream이 반환되면 계속 while문을 반복하고,
2) flag들이 반환되면 반복문을 종료하는 방식으로 동작하는 것 같다.
동일한 istream이 반환되는데 이를 사용해서 계속해서 다른 문자열을 추출할 수 있는 것은
stream은 한번 사용되면 남아있지 않고 흘러가는 것이므로 stream에서 문자열을 추출하는 것이
그 부분까지의 stream의 문자열을 사용하는 것이 돼서 계속 다음 문자열을 얻을 수 있는 것 같다.

흔히 getline을 써오던 방식으로는 아마 cin과 비슷한 용도로
getline(cin, str); 이런식으로 사용했을 것 같다.
이는 살펴보면, console input stream으로부터 줄바꿈이 발생하거나 EOF가 발생할 때 까지 추출하여 str변수에 담는 것을 의미하므로
어떤 경우에는 cin과 유사하게 동작한다.

 

  • 이를 vector에 저장하기
    istringstream iss3(str);
    vector<string> tokens;
    while(getline(iss3, token, ' ')){
        tokens.push_back(token);
    }

token에 담긴 문자열을 사용하는 것은 while문 내부 블록안에서 사용해야한다.
token값을 매번 반복할 때마다 갱신되므로 vector에 잘린 문자열을 담으려면 while문 안에서 vector에 token을 넣어주면 된다.

string.find, substr 사용

    //방법2 : string.find, substr 사용
    
    size_t previous, current;
    //인덱스 0번부터 찾기 시작
    previous = 0;
    //구분자 위치(인덱스)
    current = strDivByComma.find(",");
    
    //string.find는 문자를 찾지 못하면 npos를 반환함
    while(current != string::npos){
        //substr(start, length)
        token = strDivByComma.substr(previous, current-previous);
        cout << token << "\n";
        
        //previous 위치를 current(구분자)다음 위치로 이동
        previous = current+1;
        //previous위치 부터 ,를 찾는다.
        current = strDivByComma.find(",",previous);
    }
    
    //마지막 구분 문자열 출력
    token = strDivByComma.substr(previous,current-previous);
    cout << token << "\n";

 

두번째방법을 사용하면 구분자가 2개 이상일 때를 처리할 수 있는데

예를들어 cpp,java,python.swift를 , 혹은 . 을 기준으로 구분해야 한다면

find(",", previous) 와 find(".",previous) 중 작은 값을 current에 대입하면 될 것 같다.

 

 

참고

https://jhnyang.tistory.com/107

 

C언어 문자열 istream::getline()과 C++ string의 getline()! 한 줄 읽는 함수가 두 개?

[C언어, C++언어, JAVA언어 포스팅 링크, 라이브러리 함수 모음 링크] [C/C++] 포스팅에 들어가기 전 cstring vs string.h vs string 스트링클래스 차이(C-strings vs std::string) 이 포스팅을 먼저 읽고 보길..

jhnyang.tistory.com

https://makedotworld.tistory.com/28

 

[C++] C++에서 string 문자열을 받아와 split 하기

C++로 알고리즘 문제를 풀다 보면 다른 언어에 비해 구현하기 불편한 부분이 은근 많다. Java의 split 함수와 같이 작관적이고 쓰기 간편한 함수가 있었으면 좋겠지만, C++에서는 되게 다양한 방법으

makedotworld.tistory.com

 

728x90