C++ 正規表現で文字列の分割(split)【std::regex_token_iterator】

C++の正規表現で文字列の分割を実現する際には、# std::regex_token_iterator イテレータクラスを用いるのが有効です。

// #include <regex>   // std::regex, std::sregex_token_iterator
// #include <vector>  // std::vector
std::vector<std::string> v = {};

std::string s = "a-b-c";   // 分割対象の文字列
std::regex separator{"-"}; // 分割用のセパレータ
auto ite = std::sregex_token_iterator(s.begin(), s.end(), separator, -1);
auto end = std::sregex_token_iterator();
while (ite != end) {
  v.push_back(*ite++);     // 分割文字列を格納
}

v; // v == {"a", "b", "c"}

sregex_token_iteratorstd::string型文字列用のイテレータです。C言語スタイルの文字列を分割表示したい場合には、cregex_token_iteratorを用います。

const char *s = "a-b-c";
std::regex sep{"-"};
for (std::cregex_token_iterator end, ite{s, s + strlen(s), sep, -1}; ite != end; ++ite) {
  printf("%s", (*ite).str().c_str());
}
printf("\n"); // 出力結果: "abc\n"

アルゴリズム系の関数(std::copy, std::for_each)を用いることでより簡潔な記述を実現することもできます。

// #include <algorithm> // std::copy, std::for_each
std::string s = "a-b-c";
std::regex sp{"-"};
std::sregex_token_iterator begin{s.begin(), s.end(), sp, -1}, end;

/* 分割文字列の取得と配列への格納 */
std::vector<std::string> v = {};
std::copy(begin, end, std::back_inserter(v));
v; // v == {"a", "b", "c"}

/* 分割文字列の表示 */
std::for_each(begin, end, [](auto&& s) { std::cout << s; });
std::cout << std::endl; // 出力結果: "abc\n"

std::regex_token_iterator

regex_token_iteratorはサブマッチを走査するためのイテレータクラスです。

#include <regex>
regex_token_iterator(Ite begin, Ite end, regex pattern, int submatch = 0, match_flag_type = match_default);

コンストラクタ呼び出し時の第一引数と第二引数には、検索先の文字列のイテレータを指定します。第三引数には検索したい正規表現のパターンを記述します。第四引数を省略した場合、自身のイテレータの参照値はマッチ全体を表すサブマッチとなります。

std::string s = "a-b-c";
std::regex t{"-([a-z])"};
auto ite = std::sregex_token_iterator(s.begin(), s.end(), t);
const std::ssub_match& m = *ite; // サブマッチの取得
m.str();        // "-b"
(*++ite).str(); // "-c"

個別にキャプチャしたサブマッチを取得したい場合には、第四引数にサブマッチのインデックスを指定します。

インデックスイテレータの値備考
0全体のサブマッチstd::match_results<T>{}[0] に相当
1一つ目のサブマッチstd::match_results<T>{}[1] に相当
nN個目のサブマッチ以下省略
-1マッチしなかった箇所のサブマッチサブマッチと同等に表現(std::sub_match<T>)
std::string s = "a-b-c+d";
std::regex t{"(-)([a-z])"};
for (std::sregex_token_iterator e, i{begin(s), end(s), t, 0}; i != e; ++i)
  std::cout << *i; // 出力順: "-b", "-c"
for (std::sregex_token_iterator e, i{begin(s), end(s), t, 1}; i != e; ++i)
  std::cout << *i; // 出力順: "-" , "-"
for (std::sregex_token_iterator e, i{begin(s), end(s), t, 2}; i != e; ++i)
  std::cout << *i; // 出力順: "b" , "c"
for (std::sregex_token_iterator e, i{begin(s), end(s), t, -1}; i != e; ++i)
  std::cout << *i; // 出力順: "a", "+d"

コンストラクタ呼び出し時と++演算子によるインクリメントの度に検索が行われます。検索が終了したかどうかの判定は、空のイテレータとの比較によって実現します。

std::string s = "abc#";
std::regex t{"[a-z]"};
auto ite = std::sregex_token_iterator(s.begin(), s.end(), t);
auto end = std::sregex_token_iterator();

++ite;      // 二つ目の一致を検索 (*ite == "b")
ite == end; // false
++ite;      // 三つ目の一致を検索 (*ite == "c")
++ite;      // 四つ目の一致を検索 (`#`は一致しないため`*ite`は不定)
ite == end; // true            (これ以上検索は行えない状態)
// (*ite).str(); // 不一致時のイテレータへの参照はクラッシュの危険性があるため注意

広告