Ideal Reality

パソコンのある生活を良くするためのサイト

2019年6月21日 15時40分

[C++]文字列を任意の文字列で分割する

C++のstd::stringはC言語のchar[]と比べてすごく扱いやすいですが、それでもJavaや最近の言語と比べるとやはり機能は劣ります。

std::stringに文字列を任意の文字列で分割して配列やイテレータに変換するメソッドがないので、自分で作る必要があります。とは言っても、ループで回せば簡単に作れるので、そのサンプルを紹介します。

対応はC++11以降です。実際に使用する時は名前空間に注意してください。

スポンサーリンク

forループで回す

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str("item1,item2,item3"), separator(",");

    string tstr = str + separator;
    long l = tstr.length(), sl = separator.length();
    string::size_type pos = 0, prev = 0;
    for (;pos < l && (pos = tstr.find(separator, pos)) != string::npos; prev = (pos += sl)) {
        string item = tstr.substr(prev, pos - prev);
        cout << item << endl;
    }
    
    return 0;
}

結果

$ ./a.out 
item1
item2
item3

findメソッドでseparatorを検索し、見つかったら前回のseparatorの次の文字(初回は0文字目)から見つかったseparatorの前までの文字列をsubstrで取得します。

でも、そのままだと末尾の要素が取れないので、分割元の文字列の末尾にseparatorを追加してます。(末尾追加せずに行うと条件分岐が複雑になってしまうため、この手法をとった)

もちろんseparatorが複数文字からなる文字列でも問題ありません。

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str("item1,item2,item3"), separator("tem");

    string tstr = str + separator;
    long l = tstr.length(), sl = separator.length();
    string::size_type pos = 0, prev = 0;
    for (;pos < l && (pos = tstr.find(separator, pos)) != string::npos; prev = (pos += sl)) {
        string item = tstr.substr(prev, pos - prev);
        cout << item << endl;
    }
    
    return 0;
}

結果

% ./a.out         
i
1,i
2,i
3

ちなみに、separatorを空文字列にしてしまうと無限ループに陥るのでご注意ください。

separatorが1文字の場合

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str("item1,item2,item3"), separator(",");

    string::size_type pos = 0, prev = 0;
    string tstr = str + separator;
    for (;pos < tstr.length() && (pos = tstr.find(separator, pos)) != string::npos; prev = ++pos) {
        string item = tstr.substr(prev, pos - prev);
        cout << item << endl;
    }
    
    return 0;
}

少し簡潔に書けます。

スポンサーリンク

split関数

頻繁に使う場合は、文字列の配列を返すsplit関数を定義してもいいかもしれません。

#include <iostream>
#include <string>
#include <vector>

using namespace std;

vector<string> split(string str, string separator) {
    if (separator == "") return {str};
    vector<string> result;
    string tstr = str + separator;
    long l = tstr.length(), sl = separator.length();
    string::size_type pos = 0, prev = 0;
    
    for (;pos < l && (pos = tstr.find(separator, pos)) != string::npos; prev = (pos += sl)) {
        result.emplace_back(tstr, prev, pos - prev);
    }
    return result;
}

int main() {
    string str = "item1,item2,item3";
    vector<string> ary = split(str, ",");
    for (int i = 0; i < ary.size(); i++) {
        cout << ary[i] << endl;
    }
    
    return 0;
}

結果

$ ./a.out         
item1
item2
item3

こっちにはseparator==””の判定入れました。

スポンサーリンク

コメント

投稿されたコメントはありません

名前

コメント

関連する投稿