C++のgetlineでstringをsplitする際の注意点
C++においてstringをある文字で分割したい場合に, getlineを使って実装する例が検索するとよく出てくるが特殊な場合に罠に陥るので注意. 例えば以下のような実装(https://faithandbrave.hateblo.jp/entry/2014/05/01/171631 を一部改変).
#include <iostream> #include <string> #include <sstream> #include <vector> std::vector<std::string> split(const std::string& input, char delimiter) { std::istringstream stream(input); std::string field; std::vector<std::string> result; while (std::getline(stream, field, delimiter)) { result.push_back(field); } return result; } int main() { const std::string input = "aaa,bbb,ccc"; for (const std::string& s : split(input, ',')) { std::cout << "'" << s << "'" << std::endl; } }
これはうまくいき, aaa, bbb, cccの3つに分割される.
だが, inputを"aaa,bbb,ccc,"とした場合は要素数は4ではなく3になり, 上の例と同じ結果になってしまう. "aaa,bbb,ccc, "のように空白を置けば4つ目の要素" "が正しくとれる.
末尾以外に空文字列を入れた場合には正しく動作するので厄介 (inputが"aaa,bbb,,ccc"など).
https://onlinegdb.com/BJDaGpcWm
追記:
そもそもinputが空文字列""であった場合の動作はどうあるべきなのだろうか. この例でいえば, 空文字列に対しては空のベクトルを返すため, 空文字からなる長さ1のベクトルは扱うことができない. delimiterを含む文字列を要素とする場合のように, 明示的にquoteするとかしなければいずれにせよ, 空文字は正しく扱うことができないと考えたほうが良いのだろう.