getline()で文字列分割する方法

2019年8月22日プログラミングC++, Tips, 文字列処理

C++で文字列を分割する場合は,find系統の関数を使って自作のsplit関数を実装することが一般的なのかと思います.

今回は,もっと簡単に文字列分割する方法を紹介します.

ずばり,「getline()」を使います.

この関数は元々「getline(cin, str)」のように,標準入力cinで文字列を1行取得して,既に宣言されている文字列strに代入するという処理によく使われます.

ただし,1行の中にスペースやカンマなどのデリミタが含まれており,それらを用いた分割を行いたい場合にも,実は使用可能です.(ということを最近知りました)

標準的な使い方

今回,分割対象の文字列を以下とします.
1行だけで,スペースによって区切られています.

A B C D E

スペースで分割し,vectorに格納します.

#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
int main(void){
    vector<string> v;                  // 分割した文字列を格納するvector
    string str, s;                      
    str = "A B C D E"                  // 分割対象の文字列str
    stringstream ss{str};              // 入出力可能なsstreamに変換
    while ( getline(ss, s, ' ') ){     // スペース(' ')で区切って,格納
        v.push_back(s);
    }
    for (const string& s : v){         // vの中身を出力
        cout << s << endl;
    }
}

実行結果は以下の通りです.
しっかり分割できていますね.

A
B
C
D
E

ポイントは,stringstreamを使うことです.

分割対象の文字列を,stringstreamに変換します.

while ( getline(ss, s, ' ') ) の部分で,ssの中からスペース(’ ')手前までの文字列をsとして取得し,それをvに代入しています.

標準入力から取得した文字列の分割

通常の「getline(cin,str)」で対象文字列を一旦取得しておき,それをstringstream(ss)に変換してから,「getline(ss,s,’ ')」を実行します.

#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
int main(void){
    vector<string> v;                  
    string str, s;                      
    getline(cin,str);               
    stringstream ss{str};             
    while ( getline(ss, s, ' ') ){    
        v.push_back(s);
    }
    for (const string& s : v){        
        cout << s << endl;
    }
}

標準的な方法における「str = “A B C D E"」を「getline(cin,str)」にかえただけですね.

これを見て,2回もgetline()呼ぶ必要なくない?
「getline(cin,str,’ ')」でいいんでないの?
と思われるかもしれません.

しかし,以下のような例ではうまくいきません.

#include <iostream>
#include <vector>
using namespace std;
int main(void){
    vector<string> v;                  
    string str, s;                      
    while (getline(cin, str, ' ')){
        v.push_back(str);
    };          
    for (const string& s : v){
        cout << s << endl;
    }
}

これを実行すると,シェルで文字列を打ち込み,Enterを押しても改行されるだけで,入力を求められ続けます.
つまり,whileのおかげで入力が終わりません(笑)

だからといって,whileを取り除いた以下の例もうまくいきません.

#include <iostream>
using namespace std;
int main(void){
    vector<string> v;                  
    string str;                      
    getline(cin, str, ' '));
    cout << str << endl;
}

この場合,仮に「A B C D」と入力しても,最初の「A」しか取得できません.

おわりに

split関数を自作するのが面倒な方は,getline()を使ってみてはいかがでしょうか?