SRELLの使い方

 SRELLの説明という形を採ってはいますが、特に断りがなければこの頁の内容はC++11以降のstd::regexにも当てはまります。

SRELLのメンバ一覧

主なもの

付属物的なもの

 正規表現検索を行う際の大まかな流れは次の通りです。

  1. basic_regex<charT, traits>型のインスタンスを作成。正規表現文字列を渡してコンパイルする。
  2. 検索結果を受け取る場合、match_results<BidirectionalIterator, Allocator>型のインスタンスを用意する。単にマッチするか否かが分かれば充分な時は不要。
  3. algorithm(regex_match(), regex_search())に上2つのインスタンスと検索対象文字列とを渡す。文字列に正規表現がマッチした場合、その部分や()によって捕獲された部分の位置情報が、参照渡ししておいたmatch_results型インスタンスへと書き込まれる。

主なクラス

template <class charT, class traits = regex_traits<charT> >
class basic_regex;

 正規表現オブジェクトの作成・保持を行うクラスです。次のような型がtypedefされています。

typedef basic_regex<char> regex;
typedef basic_regex<wchar_t> wregex;

//  ここから下はSRELL独自のもの。
typedef basic_regex<char, u8regex_traits<char> > u8cregex;

//  char8_t対応かどうかでu8regexの定義を変える。
#if defined(__cpp_char8_t)
    typedef basic_regex<char8_t, u8regex_traits<char8_t> > u8regex;
#else
    typedef u8cregex u8regex;
#endif

//  C++11対応コンパイラ用。
typedef basic_regex<char16_t, u16regex_traits<char16_t> > u16regex;
typedef basic_regex<char32_t> u32regex;

//  wchar_tの大きさにより、wregex を u32wregex か u16wregex かにtypedefする。
#if defined(WCHAR_MAX)
    #if WCHAR_MAX >= 0x10ffff
        typedef wregex u32wregex;
    #elif WCHAR_MAX >= 0xffff
        typedef basic_regex<wchar_t, u16regex_traits<wchar_t> > u16wregex;
    #endif
#endif
		

 std::regexにあるものはregex, wregexの2つだけで、u(8c?|16w?|32w?)というprefixが付いているものはSRELLの拡張です。

 basic_regexクラスで正規表現オブジェクトを作成するには、

 という3つの方法があり、それぞれに「引数として文字列のポインタまたはbasic_string型インスタンスの参照を渡し、新規にコンパイルする方法」「basic_regex型インスタンスの参照を渡してコピーする方法」「同moveする方法(C++11以降)」「initializer_listを渡す方法(C++11以降)」があります。

コンストラクタ

basic_regex(const basic_regex& e);  //  コピーコンストラクタ。

basic_regex(basic_regex&& e) noexcept;  //  C++11以降。

explicit
basic_regex(const charT* p, flag_type f = regex_constants::ECMAScript);

basic_regex(const charT* p, size_t len, flag_type f = regex_constants::ECMAScript);

template <class ST, class SA>
explicit
basic_regex(const std::basic_string<charT, ST, SA>& p, flag_type f = regex_constants::ECMAScript);

template <class ForwardIterator>
basic_regex(ForwardIterator first, ForwardIterator last, flag_type f = regex_constants::ECMAScript);

basic_regex(initializer_list<charT> il, const flag_type f = regex_constants::ECMAScript); //  C++11以降。
		

operator=

basic_regex& operator=(const basic_regex&); //  代入演算子。

basic_regex& operator=(basic_regex&&) noexcept;     //  C++11以降。

basic_regex& operator=(const charT* ptr);

template <class ST, class SA>
basic_regex& operator=(const std::basic_string<charT, ST, SA>& p);

basic_regex& operator=(initializer_list<charT> il);   //  C++11以降。
		

assign函数

basic_regex& assign(const basic_regex&);

basic_regex& assign(regex_basic&&) noexcept;   //  C++11以降。

basic_regex& assign(const charT* ptr, flag_type f = regex_constants::ECMAScript);

basic_regex& assign(const charT* p, size_t len, flag_type f = regex_constants::ECMAScript);

template <class ST, class A>
basic_regex& assign(const std::basic_string<charT, ST, A>& s, flag_type f = regex_constants::ECMAScript);

template <class InputIterator>
basic_regex& assign(InputIterator first, InputIterator last, flag_type f = regex_constants::ECMAScript);

basic_regex& assign(initializer_list<charT> il, const flag_type f = regex_constants::ECMAScript); //  C++11以降。
		

 flag_typeという型は、regex_constants::syntax_option_typeをbasic_regex内でtypedefしたものです。その名が示す通りコンパイル時の文法解釈を指定するためのフラグで、次のような値が定義されています。

regex_constants::syntax_option_type

namespace regex_constants
{
    static const syntax_option_type icase;
        //  大文字小文字を同一視する。ECMAScriptやPerlの //i に相当。

    static const syntax_option_type multiline;
        //  ^や$が行頭・行末にもマッチするようにする。
        //  ECMAScriptやPerlの //m に相当。

    static const syntax_option_type dotall;
        //  SRELL 2の独自拡張。'.' があらゆる文字にマッチするようにする。
        //  ECMAScript 2018以降のRegExpやPerlの //s に相当。
}
		

 これらは | (or) で区切ることによって同時に指定することも出来ます。
 std::regexではこの他の値も定義されていますが、SRELLでは上記のもの以外は認識されません(定義そのものはされているので指定してもエラーにはならず)。

 これらはbasic_regexクラス内でflag_type型の値としても定義されていますので、"regex_constants::icase" は "regex::icase" のように書くことも出来ます(regex::のところは実際に使う型に合わせる)。

 basic_regexクラスのメンバのうち、主なものは次の通りです。

unsigned mark_count() const;
    //  正規表現内部に存在する「文字列を捕獲する括弧」の数を返す。

flag_type flags() const;
    //  正規表現コンパイル時に指定したflagを返す。

locale_type imbue(locale_type loc);
    //  オブジェクトのlocaleを指定する。返値は変更前のlocale。
    //  locale_type は、traits::locale_type をtypedefしたもの。

locale_type getloc() const;
    //  オブジェクトのlocaleを返す。

void swap(basic_regex& e);
    //  正規表現オブジェクトの交換をする。

std::size_t limit_counter;
    //  SRELL拡張。詳細は「長考対策」を参照。
		

 localeはicase検索で使うtolowerや、\d, \s, \wなどで使うis系函数の挙動を変えるためのもので、std::regexでは重要な役割を果たします。しかしSRELLはECMAScriptベースであることからlocale周りの実装がすべて省略されています。imbueを行っても何も変わらず、getlocが返すのは常に現在の大域localeです(std::locale()を返す)。

 basic_regexに関しては、クラスメンバ以外にも次のようなものがあります。

template <class charT, class traits>
void swap(basic_regex<charT, traits>& lhs, basic_regex<charT, traits>& rhs);
		

エラー発生時には

 正規表現をコンパイルしている最中にエラーが発生すると、regex_errorクラスがthrowされます。regex_errorクラスはstd::runtime_errorクラスを継承したもので、メンバはエラー番号を読み出す regex_constants::error_type code() という函数のみです。

 srell::basic_regexがthrowするエラー一覧は次の通りです。

namespace regex_constants
{
    static const error_type error_escape;       //  解釈不可能な\、または\で終わっている。
    static const error_type error_backref;      //  \n番に該当する括弧がない。
    static const error_type error_brack;        //  []が非対称。
    static const error_type error_paren;        //  ()が非対称。
    static const error_type error_brace;        //  {}が非対称。
    static const error_type error_badbrace;     //  {3,2}など範囲指定がおかしい。
    static const error_type error_range;        //  [b-a]など範囲指定がおかしい。
    static const error_type error_badrepeat;    //  *?+{の前に変なものがある。

    //  以下はSRELL拡張。
    static const error_type error_lookbehind;   //  SRELL 1のみ。戻り読みが固定幅に非ず。
}
		

 このようにbasic_regexは、正規表現におかしなところがあるとthrowすることでその旨を伝えてきます。そのため特にユーザに正規表現を入力させるようなアプリケーションの場合、try~cacheは必須です。

Algorithm

 Algorithmにはregex_match(), regex_search(), regex_replace()の3種類があります。

 文字列の中から正規表現に合致する部分を探し出し、見つかったらtrue、そうでないならfalseを返します。
 引数には、

  1. 検索対象文字列
  2. 結果を受け取るためのmatch_results型インスタンスの参照(省略可能)
  3. 正規表現オブジェクトが収められたbasic_regex型インスタンスの参照
  4. regex_constants::match_flag_type 型のマッチフラグオプション(省略可能)

 をこの順番で渡します。
 文字列の渡し方には、「[begin, end)のiteratorペアを渡す」「文字列のポインタを渡す」「basic_string型インスタンスの参照を渡す」の3種類があり、それぞれに「引数としてmatch_results型インスタンスの参照を渡す・渡さない」の選択肢があるため、3×2で計6種類の書式が存在します。

template <class BidirectionalIterator, class Allocator, class charT, class traits>
bool regex_search(
    BidirectionalIterator first,
    BidirectionalIterator last,
    match_results<BidirectionalIterator, Allocator>& m,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);

template <class BidirectionalIterator, class charT, class traits>
bool regex_search(
    BidirectionalIterator first,
    BidirectionalIterator last,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);
    //  マッチするかどうかだけ知りたい時は、match_resultsは渡さずとも良い。

template <class charT, class Allocator, class traits>
bool regex_search(
    const charT* str,
    match_results<const charT*, Allocator>& m,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);

template <class charT, class traits>
bool regex_search(
    const charT* str,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);
    //  上からmatch_resultsを省略したもの。

template <class ST, class SA, class Allocator, class charT, class traits>
bool regex_search(
    const std::basic_string<charT, ST, SA>& s,
    match_results<typename std::basic_string<charT, ST, SA>::const_iterator, Allocator>& m,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);

template <class ST, class SA, class charT, class traits>
bool regex_search(
    const std::basic_string<charT, ST, SA>& s,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);
    //  上からmatch_resultsを省略したもの。
		

 引数としてmatch_results型インスタンスmの参照を渡しておいた場合、正規表現に合致する部分が文字列中に見つかった時には、マッチした位置の情報をmにセットしたうえでtrueを返してきます。

 検索オプションを指定するregex_constants::match_flag_type型には、次のようなフラグオプション値が定義されています。これらは | (or) で区切ることによって同時に複数指定することも出来ます。

namespace regex_constants
{
    typedef bitmask_type match_flag_type;

    static const match_flag_type match_default = 0;
    static const match_flag_type match_not_bol;
        //  引数として渡した文字列の先頭に^がマッチしないようにする。

    static const match_flag_type match_not_eol;
        //  引数として渡した文字列の末尾に$がマッチしないようにする。

    static const match_flag_type match_not_bow;
        //  引数として渡した文字列の先頭を単語の始まりと見なさせない。\bに影響を及ぼす。

    static const match_flag_type match_not_eow;
        //  引数として渡した文字列の末尾を単語の終わりと見なさせない。\bに影響を及ぼす。

    static const match_flag_type match_not_null;
        //  空文字列にマッチさせない。

    static const match_flag_type match_continuous;
        //  引数として渡した文字列の先頭からマッチするかどうかのみ調べる。

    static const match_flag_type match_prev_avail;
        //  引数として渡した文字列先頭の一文字前 (--first) は有効な位置。
        //  このフラグがセットされると、上のmatch_not_bol, match_not_bowは無視される。
}
		

 この他にもstd::regexの仕様書には match_any というフラグが存在しますが、SRELLでは機能しません(定義自体はされています)。

 アルゴリズムがthrowするエラー一覧は次の通りです。

namespace regex_constants
{
    static const error_type error_complexity;   //  複雑すぎる正規表現。
    static const error_type error_stack;        //  メモリ不足。
}
		

regex_match()

 正規表現が対象文字列全体とぴったり合致するならtrue、そうでないならfalseを返します。それ以外はregex_search()と同じです。

 書式も次の通り、regex_searchのそれと同じです。

template <class BidirectionalIterator, class Allocator, class charT, class traits>
bool regex_match(
    BidirectionalIterator first,
    BidirectionalIterator last,
    match_results<BidirectionalIterator, Allocator>& m,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);

template <class BidirectionalIterator, class charT, class traits>
bool regex_match(
    BidirectionalIterator first,
    BidirectionalIterator last,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);

template <class charT, class Allocator, class traits>
bool regex_match(
    const charT* str,
    match_results<const charT*, Allocator>& m,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);

template <class charT, class traits>
bool regex_match(
    const charT* str,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default)

template <class ST, class SA, class Allocator, class charT, class traits>
bool regex_match(
    const std::basic_string<charT, ST, SA>& s,
    match_results<typename std::basic_string<charT, ST, SA>::const_iterator, Allocator>& m,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);

template <class ST, class SA, class charT, class traits>
bool regex_match(
    const std::basic_string<charT, ST, SA>& s,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);
		

regex_replace()

 1. 検索対象文字列、2. 正規表現オブジェクト、3. 書式文字列の3つを渡すと、検索対象文字列の中から正規表現に合致する箇所を探し出し、その結果を書式文字列の中へ流し込んで返してくる函数です。いわゆる「置換」と考えても良いのですが、函数の呼出後も検索対象文字列は元の状態のまま残り、置換後の文字列はreturnされてくるという点で純粋な置換処理とは異なります。

 検索対象文字列の渡し方には例によって「[begin, end)のiteratorペアを渡す」「文字列のポインタを渡す」「basic_string型インスタンスの参照を渡す」の3種類があります。このうち「iteratorペアを渡す」という方法を選んだ場合、結果は第1引数で指定したOutputIteratorに対して出力されます。それ以外の2種類を選んだ場合、結果はbasic_string型のインスタンスに詰め込まれてreturnされてきます。
 これら3種類にそれぞれ「書式を表す文字列をconst basic_string<charT>&型で渡すか、const charT*型で渡すか」という選択肢があるため、引数の渡し方には3×2で計6通りが存在します。

template <class OutputIterator, class BidirectionalIterator, class traits, class charT, class ST, class SA>
OutputIterator regex_replace(
    OutputIterator out,
    BidirectionalIterator first,
    BidirectionalIterator last,
    const basic_regex<charT, traits>& e,
    const std::basic_string<charT, ST, SA>& fmt,
    regex_constants::match_flag_type flags = regex_constants::match_default);
    //  [first, last)は検索対象文字列、eは正規表現オブジェクト。
    //  fmtの書式に従い、マッチの結果をoutに出力する。

template <class OutputIterator, class BidirectionalIterator, class traits, class charT>
OutputIterator regex_replace(
    OutputIterator out,
    BidirectionalIterator first,
    BidirectionalIterator last,
    const basic_regex<charT, traits>& e,
    const charT* fmt,
    const regex_constants::match_flag_type flags = regex_constants::match_default);
    //  fmtがcharT*型になっていることを除けば上に同じ。

template <class traits, class charT, class ST, class SA, class FST, class FSA>
std::basic_string<charT, ST, SA> regex_replace(
    const std::basic_string<charT, ST, SA>& s,
    const basic_regex<charT, traits>& e,
    const std::basic_string<charT, FST, FSA>& fmt,
    regex_constants::match_flag_type flags = regex_constants::match_default);
    //  sは検索対象文字列、eは正規表現オブジェクト。
    //  検索結果をfmtの書式に従って整形したものをreturnする。

template <class traits, class charT, class ST, class SA>
std::basic_string<charT, ST, SA> regex_replace(
    const std::basic_string<charT, ST, SA>& s,
    const basic_regex<charT, traits>& e,
    const charT* fmt,
    const regex_constants::match_flag_type flags = regex_constants::match_default)
    //  fmtがcharT*型になっていることを除けば上に同じ。

template <class traits, class charT, class ST, class SA>
std::basic_string<charT> regex_replace(
    const charT* s,
    const basic_regex<charT, traits>& e,
    const std::basic_string<charT, ST, SA>& fmt,
    const regex_constants::match_flag_type flags = regex_constants::match_default);
    //  sは検索対象文字列へのポインタ、eは正規表現オブジェクト。
    //  検索結果をfmtの書式に従って整形したものをreturnする。

template <class traits, class charT>
std::basic_string<charT> regex_replace(
    const charT* s,
    const basic_regex<charT, traits>& e,
    const charT* fmt,
    const regex_constants::match_flag_type flags = regex_constants::match_default);
    //  fmtがcharT*型になっていることを除けば上に同じ。
		

 使用例を示します。

int main()
{
    srell::regex exp("\\d(\\d)(\\d)"); //  正規表現。
    std::string str("123-456-789");  //  検索対象。
    std::string fmt("マッチした部分 = $&\n1番目の括弧 = $1\n2番目の括弧 = $2\n\n");  //  書式。

    std::ostreambuf_iterator<char> os(std::cout);
    srell::regex_replace(os, str.begin(), str.end(), exp, fmt, srell::regex_constants::format_no_copy);

    //  上は次のように書いても同じ結果がもたらされる。
    //  std::cout << srell::regex_replace(str, exp, fmt, srell::regex_constants::format_no_copy) << std::endl;

    return 0;
}

実行結果:
マッチした部分 = 123
1番目の括弧 = 2
2番目の括弧 = 3

マッチした部分 = 456
1番目の括弧 = 5
2番目の括弧 = 6

マッチした部分 = 789
1番目の括弧 = 8
2番目の括弧 = 9
		

 fmt中の$&, $1, $2等が検索結果によって置き換えられています。このような置き換えの対象となるのは、$&, $`, $', $1, $2, ... などECMAScript Language Specificationの15.5.4.11で定義されているシンボルです。なお書式を表す文字列中で $ 自身を表すには $$ と書きます。

 regex_replaceの最後の引数には、regex_search()やregex_match()で使われるマッチフラグオプションに加えて次のものが指定できます。これらも | (or) で区切ることによって同時に指定することが出来ます。

static const match_flag_type format_default = 0;
static const match_flag_type format_no_copy;
    //  マッチしていない部分(&`や&'に当たる箇所)の文字列は
    //  自動的に出力しない。

static const match_flag_type format_first_only;
    //  最初にマッチした部分のみ出力する。
		

 regex_replace()は、ECMAScriptやPerlの正規表現でいうところのgオプションが既定でオンになっていて、検索対象文字列中のマッチする箇所すべてが置き換えの対象となります。先ほどの例で、regex_replace()を一回呼び出しただけにもかかわらず正規表現に該当する3箇所 ("123", "456", "789") すべてが出力されてきたのもそのためです。
 これをオフにして最初にマッチする箇所だけを対象としたい場合にはformat_first_onlyを指定します。

 また既定の振る舞いでは、最初にマッチした箇所より前方の文字列、最後にマッチした箇所より後方の文字列、マッチした箇所同士の間の文字列もそのまま出力されてきます。これをオフにしてマッチした箇所だけを対象としたい時にはformat_no_copyを指定します。

format_first_onlyとformat_no_copy
format_-
first_only
format_-
no_copy
←文字列先頭 文字列末尾→
マッチ1箇所目 マッチ2箇所目
無指定 無指定 そのまま
出力
マッチした文字列で
fmt中の$&, $1などを
置き換えて出力
そのまま
出力
マッチした文字列で
fmt中の$&, $1などを
置き換えて出力
そのまま
出力
指定あり 出力なし 出力なし 出力なし
指定あり 無指定 そのまま
出力
そのまま
出力
指定あり 出力なし 出力なし

 少し分かりづらいかと思われますので具体例を挙げます。

Perlの置換 (s/.../.../) 風の処理
//  regex_search()でPerlの s/.../.../ や s/.../.../g 風の処理を行う例。

int main()
{
    std::string str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; //  対象文字列。
    const srell::regex re("\\d{2}");
    const std::string fmt("<>");  //  書式文字列。

    //  $str =~ s/\d{2}/<>/ 風の処理(最初の1つだけ置換)。
    std::string res1 = srell::regex_replace(str, re, fmt
        , srell::regex_constants::format_first_only);

    //  $str =~ s/\d{2}/<>/g 風の処理(該当箇所はすべて置換)。
    std::string res2 = srell::regex_replace(str, re, fmt);

    //  printfを使うなら。
    std::printf("result1: %s\n", res1.c_str());
    std::printf("result2: %s\n", res2.c_str());

    //  iostreamを使うなら。
    std::cout << "result1: " << res1 << std::endl;
    std::cout << "result2: " << res2 << std::endl;

    //  ここで str.swap(res1) または str.swap(res2) とすることで「置換」になる。

    return 0;
}

実行結果:
result1: ABCDEFGHIJKLMNOPQRSTUVWXYZ<>23456789abcdefghijklmnopqrstuvwxyz
result2: ABCDEFGHIJKLMNOPQRSTUVWXYZ<><><><><>abcdefghijklmnopqrstuvwxyz
			

 この例において、正規表現reが検索対象文字列strに対して最初にマッチするのは "01" の部分です。その段階でregex_replace()はまずformat_no_copyが指定されているかどうかを調べ、指定されていなければマッチした箇所(この場合 "01")より前の文字列("ABC...XYZ")を出力します。
 そして次に、マッチした箇所を書式文字列 (fmt) の指定に従って置き換えます。ところがこの例では書式文字列fmtの中に "$&" が含まれていませんので、正規表現にマッチした箇所は出力対象に含まれません。そのため、結果として正規表現にマッチした箇所が書式文字列 "<>" そのものに置き換えられてしまうことになります。
 これが終わるとregex_replace()はformat_first_onlyが指定されているかどうかを調べます。そして指定されていれば再度format_no_copyが指定されているか調べて、指定されていればそこで処理を終え、指定されていなければマッチした箇所より後の文字列("234...xyz")をそのまま出力してから処理を終えます。こうして出力されたのが、result1の文字列です。

 format_first_onlyが指定されていなかった場合、regex_replace()は今回マッチした箇所の次("1" と "2" の間)を起点にして、再度正規表現reにマッチする箇所があるかどうかを調べます。そしてさらに見つかった場合、format_no_copyが指定されていなければ、起点("01"の次)から今回見つかった箇所("23")の間の文字列を出力します。
 この繰り返しによって "01", "23", "45", "67", "89" の部分が "<>" によって置き換えられたものが出力されてゆき、結果、result2の文字列が出来上がります。

 先述の通り、いずれの場合も結果はOutputIteratorへ出力またはstd::basic_string型のインスタンスで返されてきます。Perlのように元の文字列が置き換わるのではないことにご注意ください。前記サンプルコード中のコメントにもありますように、置換に相当する処理を行うには最後にswap()または代入をする必要があります。

 上記のものの他、std::regexの仕様書には format_sed というオプションフラグが定義されていますが、SRELLでは機能しません(指定自体は可能)。

 アルゴリズムは以上ですべてです。

template <class BidirectionalIterator, class Allocator = std::allocator<sub_match<BidirectionalIterator> > >
class match_results;

 正規表現検索の結果が収められるクラスです。match_resultsからは次のような型がtypedefされています。

typedef match_results<const char*> cmatch;
typedef match_results<const wchar_t*> wcmatch;
typedef match_results<std::string::const_iterator> smatch;
typedef match_results<std::wstring::const_iterator> wsmatch;

//  ここから下はSRELL独自のもの。
typedef cmatch u8ccmatch;
typedef smatch u8csmatch;

//  char8_t対応かどうかでu8[cs]matchの定義を変える。
#if defined(__cpp_char8_t)
    typedef match_results<const char8_t*> u8cmatch;
    typedef match_results<std::u8string::const_iterator> u8smatch;
#else
    typedef u8ccmatch u8cmatch;
    typedef u8csmatch u8smatch;
#endif

//  C++11対応コンパイラ用。
typedef match_results<const char16_t*> u16cmatch;
typedef match_results<const char32_t*> u32cmatch;
typedef match_results<std::u16string::const_iterator> u16smatch;
typedef match_results<std::u32string::const_iterator> u32smatch;

//  wchar_tの大きさにより、w[cs]match を u32w[cs]match か u16w[cs]match かにtypedefする。
#if defined(WCHAR_MAX)
    #if WCHAR_MAX >= 0x10ffff
        typedef wcmatch u32wcmatch;
        typedef wsmatch u32wsmatch;
    #elif WCHAR_MAX >= 0xffff
        typedef wcmatch u16wcmatch;
        typedef wsmatch u16wsmatch;
    #endif
#endif
		

 cmatch系とsmatch系とがあって少しややこしいのですが、Cconstポインタ型なのがcmatch型、basic_stringのconst_iterator型なのがsmatch型です。これらはregex_match()regex_search()に対して渡す検索対象文字列の型と一致させる必要があります

 match_resultsクラスは検索の結果を受け取るためのものということもあり、ほとんどのメンバが読み出し専用です。

regex_match(), regex_search()の結果を受けて必ず変化するもの

bool ready() const;
    //  regex_match()やregex_search()の結果をセットされたことがあるならtrueを返す。

size_type size() const;
    //  マッチした場合は正規表現中の
    //  「文字列を捕獲する(後方参照可能な)括弧」の数+1を、
    //  マッチしなかった場合は0を返す。

bool empty() const;
    //  return size() == 0;
		

 作成された直後のmatch_results型のインスタンスmは、メンバ函数ready()がfalseを返してきます。しかしひとたびregex_match()やregex_search()の結果を受けとると、マッチングの成否に関係なくm.ready()がtrueを返してくるようになります。

 m.size()の「文字列を捕獲する括弧」というのは /.+(\d+).+(abc|def)/ のような正規表現における (\d+) や (abc|def) のことです。括弧でも後から参照できない(?:)のようなものは数に入りません。
 その数が+1されるのは、検索後、正規表現全体にマッチした部分も「暗黙の0番括弧によって捕獲された」と見なす仕組みになっているためです。

 regex_match()やregex_search()は引数にmatch_results型インスタンスmへの参照が渡されてくると、マッチングに成功した際mに次の情報をセットします。

 これらのデータはすべてmatch_results::value_type型のインスタンスとしてmatch_results内部に保持されています。ちなみにこの型は後述するsub_match<BidirectionalIterator>型のtypedefです。

typedef sub_match<BidirectionalIterator> value_type;
typedef const value_type& const_reference;
//  以下略。
		

 一方マッチしなかった時には、m.ready() == true, m.size() == 0, m.empty() == true となること以外は未定義とされています。

 マッチした部分の位置情報を取り出すために、次のメンバ函数が用意されています。

regex_match, regex_searchがtrueの時のみ有効なメンバ函数

const_reference operator[](size_type n) const;
    //  sub番括弧のデータを保持するvalue_type型インスタンスへのconst参照。
    //  [0]が正規表現全体にマッチした位置、[1]以降が括弧の位置情報を保持。

const_reference prefix() const;
    //  正規表現がマッチした部分より前の部分のデータを保持するvalue_type型
    //  インスタンスへのconst参照。

const_reference suffix() const;
    //  正規表現がマッチした部分より後の部分のデータを保持するvalue_type型
    //  インスタンスへのconst参照。

difference_type position(size_type sub = 0) const;
    //  sub番括弧に捕獲された文字列の先頭位置を返す。起点は文字列全体の先頭。

difference_type length(size_type sub = 0) const;
    //  sub番括弧に捕獲された文字列の要素数を返す。

string_type str(size_type sub = 0) const;
    //  sub番括弧が捕獲した文字列を返す。

const_iterator begin() const;
const_iterator cbegin() const;
    //  0番括弧~n番括弧までのデータを保持する vector<value_type> の
    //  先頭const_iteratorを返す。

const_iterator end() const;
const_iterator cend() const;
    //  同最終const_iteratorの次を返す。つまり上のと合わせて[begin, end)。
		

 さらにSRELL 2では、名前付きキャプチャに対応するために次のようなメンバが独自に追加定義されています。引数として括弧の番号ではなく後方参照名を表す文字列を取ること以外は、前掲した同名のメンバ函数と同じ振る舞いをします。

//  SRELL 2の独自拡張。
const_reference operator[](const string_type &sub) const;
difference_type position(const string_type &sub) const;
difference_type length(const string_type &sub) const;
string_type str(const string_type &sub) const;
		

 その他、主なメンバ函数には次のようなものがあります。

template <class OutputIter>
OutputIter format(
    OutputIter out,
    const string_type& fmt,
    regex_constants::match_flag_type flags = regex_constants::format_default) const;
    //  fmtの書式に従って、現在保持している検索結果をOutputIterに出力する。

string_type format(
    const string_type& fmt,
    regex_constants::match_flag_type flags = regex_constants::format_default) const;
    //  string_type型のインスタンスをreturnするという点以外、上と同じ。

void swap(match_results&);
    //  match_resultsインスタンスの中身の交換。
		

 メンバ函数format()の引数fmtというのは、algorithmのregex_replace()で出てきたfmtと同じものです。実のところregex_replace()は、このformat()を繰り返し呼び出しているだけです。

 match_resultsクラスに関してはクラスメンバ以外にもswap()やoperator==(), operator!=()などが定義されています。

template <class BidirectionalIterator, class Allocator>
void swap(
    match_results<BidirectionalIterator, Allocator>& m1,
    match_results<BidirectionalIterator, Allocator>& m2);

template <class BidirectionalIterator, class Allocator>
bool operator==(
    const match_results<BidirectionalIterator, Allocator>& m1,
    const match_results<BidirectionalIterator, Allocator>& m2);

template <class BidirectionalIterator, class Allocator>
bool operator!=(
    const match_results<BidirectionalIterator, Allocator>& m1,
    const match_results<BidirectionalIterator, Allocator>& m2);
		

template <class BidirectionalIterator>
class sub_match : public std::pair<BidirectionalIterator, BidirectionalIterator>;

 match_resultsクラス内部で、正規表現にマッチした部分の位置情報を保持・管理するのに使われているのがこのクラスです。ライブラリを使う側がこの型のインスタンスを直接宣言する機会はまずないでしょう。match_resultsのメンバへの参照を行うのに使う場合がほとんどかと思われます。

 sub_matchからは次のような型がtypedefされています。

typedef sub_match<const char*> csub_match;
typedef sub_match<const wchar_t*> wcsub_match;
typedef sub_match<std::string::const_iterator> ssub_match;
typedef sub_match<std::wstring::const_iterator> wssub_match;

//  ここから下はSRELL独自のもの。
typedef csub_match u8ccsub_match;
typedef ssub_match u8cssub_match;

//  char8_t対応かどうかでu8[cs]sub_matchの定義を変える。
#if defined(__cpp_char8_t)
    typedef sub_match_results<const char8_t*> u8csub_match;
    typedef sub_match_results<std::u8string::const_iterator> u8ssub_match;
#else
    typedef u8ccsub_match u8csub_match;
    typedef u8cssub_match u8ssub_match;
#endif

//  C++11対応コンパイラ用。
typedef sub_match_results<const char16_t*> u16csub_match;
typedef sub_match_results<const char32_t*> u32csub_match;
typedef sub_match_results<std::u16string::const_iterator> u16ssub_match;
typedef sub_match_results<std::u32string::const_iterator> u32ssub_match;

//  wchar_tの大きさにより、w[cs]submatch を u32w[cs]submatch か u16w[cs]submatch かにtypedefする。
#if defined(WCHAR_MAX)
    #if WCHAR_MAX >= 0x10ffff
        typedef wcsub_match u32wcsub_match;
        typedef wssub_match u32wssub_match;
    #elif WCHAR_MAX >= 0xffff
        typedef wcsub_match u16wcsub_match;
        typedef wssub_match u16wssub_match;
    #endif
#endif
		

 match_resultsの場合と同じく、csub_match系とssub_match系とがあります。もっとも、match_results内部で使われているsub_match型は、value_type型やconst_reference型にtypedefされていますので、そちらを使ったほうが型の間違いが起こりにくいでしょう(新autoが使えるC++11以降ならこれすら使わないかもしれません)。

 sub_matchクラスの主なメンバは次の通りです。

BidirectionalIterator first;    //  文字列の先頭位置を指す。
BidirectionalIterator second;   //  文字列の末尾+1を指す。上のと合わせて[first, second)。
    //  この2つは継承元であるstd::pairのメンバ。

bool matched;
    //  このインスタンスが何かを捕獲しているかどうかのbool。
    //  falseの時はfirst, secondの値とも無効。

typedef typename std::iterator_traits<BidirectionalIterator>::value_type value_type;
typedef typename std::iterator_traits<BidirectionalIterator>::difference_type difference_type;

difference_type length() const;
    //  first~second間の要素数を返す。

operator std::basic_string<value_type>() const;   //  キャスト演算子。
std::basic_string<value_type> str() const;
    //  上2つはfirst~second間の文字列のコピーを返す。

int compare(const sub_match& s) const;
    //  str().compare(s.str())の結果を返す。

int compare(const std::basic_string<value_type>& s) const;
int compare(const value_type* s) const;
    //  上2つはstr().compare(s)の結果を返す。
		

 基底クラスのstd::pairから継承したfirstとsecondとが、マッチした位置ないし()で捕獲した文字列の位置を[first, second)の形で表します。

 matchedは少し注意が必要です。match_results型のインスタンスをmとした時、m[0]やm[1]などm.operator[]()のmatchedと、m.prefix(), m.suffix()のmatchedとでは意味するものが異なります。
 operator[]()におけるmatchedは、「空文字であれとにかく捕獲できたかどうか」を意味します。例えば "abc" =~ /a(.?)b|c(.?)d/ のような場合、m[1].matchedはtrueですが、m[2].matchedはfalseになります。
 一方、m.prefix()やm.suffix()のmatchedは、「自身の長さ(first~second間の長さ)が1文字以上あるかどうか」を意味します。

 sub_matchクラスに関してはクラスメンバ以外にも次のようなものがあります。

//  cout << m[0] << endl; のような表記用。
template <class charT, class ST, class BiIter>
std::basic_ostream<charT, ST>& operator<<(
    std::basic_ostream<charT, ST>& os,
    const sub_match<BiIter>& m);

//  この他、sub_match型インスタンス同士や、sub_match型インスタンスと
//  文字列のポインタ・basic_string型インスタンスとの比較を行う
//  operator函数群。数が多いので省略。
		

付属物的なクラス

template <class BidirectionalIterator, class charT = typename std::iterator_traits<BidirectionalIterator>::value_type, class traits = regex_traits<charT> >
class regex_iterator;

 コンストラクタに正規表現オブジェクトと検索対象文字列とを渡すと、regex_iterator型のインスタンスiterはすぐさま内部でregex_search()を呼び出し、最初にマッチした位置の情報を、iter内部のmatch_results型インスタンスへ書き込みます。外部からこのインスタンスへは*iterないしiter->でアクセスします。

 iterは++されると、次のマッチングポイントを探すべく再度regex_search()を呼び出します。その結果マッチする箇所が見つかったなら先ほどと同じことを繰り返します。
 一方マッチする箇所がなかった場合、iterは "end-of-sequence iterator" という特別な状態のiteratorへと移行します。

 regex_iteratorはforward iteratorに分類されますので、--iterは出来ません。

 regex_iteratorからは次のような型がtypedefされています。通常はこのうちのいずれかを使用します。

typedef regex_iterator<const char *> cregex_iterator;
typedef regex_iterator<const wchar_t *> wcregex_iterator;
typedef regex_iterator<std::string::const_iterator> sregex_iterator;
typedef regex_iterator<std::wstring::const_iterator> wsregex_iterator;

//  ここから下はSRELL独自のもの。
typedef regex_iterator<const char *,
    typename std::iterator_traits<const char *>::value_type,
    u8regex_traits<typename std::iterator_traits<const char *>::value_type> >
    u8ccregex_iterator;
typedef regex_iterator<std::string::const_iterator,
    typename std::iterator_traits<std::string::const_iterator>::value_type,
    u8regex_traits<typename std::iterator_traits<std::string::const_iterator>::value_type> >
    u8csregex_iterator;

//  char8_t対応かどうかでu8[cs]regex_iteratorの定義を変える。
#if defined(__cpp_char8_t)
    typedef regex_iterator<const char8_t *> u8cregex_iterator;
    typedef regex_iterator<std::u8string::const_iterator> u8sregex_iterator;
#else
    typedef u8ccregex_iterator u8cregex_iterator;
    typedef u8csregex_iterator u8sregex_iterator;
#endif

//  C++11対応コンパイラ用。
#if defined(SRELL_CPP11_CHAR1632_ENABLED)
    typedef regex_iterator<const char16_t *> u16cregex_iterator;
    typedef regex_iterator<const char32_t *> u32cregex_iterator;
    typedef regex_iterator<std::u16string::const_iterator> u16sregex_iterator;
    typedef regex_iterator<std::u32string::const_iterator> u32sregex_iterator;
#endif

#if defined(WCHAR_MAX)
    #if WCHAR_MAX >= 0x10ffff
        typedef wcregex_iterator u32wcregex_iterator;
        typedef wsregex_iterator u32wsregex_iterator;
    #elif WCHAR_MAX >= 0xffff
        typedef regex_iterator<const wchar_t *,
            typename std::iterator_traits<const wchar_t *>::value_type,
            u16regex_traits<typename std::iterator_traits<const wchar_t *>::value_type> >
            u16wcregex_iterator;
        typedef regex_iterator<std::wstring::const_iterator,
            typename std::iterator_traits<std::wstring::const_iterator>::value_type,
            u16regex_traits<typename std::iterator_traits<std::wstring::const_iterator>::value_type> >
            u16wsregex_iterator;
    #endif
#endif
		

 regex_iteratorクラスのメンバは次の通りです。

typedef basic_regex<charT, traits> regex_type;
typedef match_results<BidirectionalIterator> value_type;
typedef std::ptrdiff_t difference_type;
typedef const value_type* pointer;
typedef const value_type& reference;
typedef std::forward_iterator_tag iterator_category;

regex_iterator();

regex_iterator(const BidirectionalIterator a, const BidirectionalIterator b,
    const regex_type& re,
    const regex_constants::match_flag_type m = regex_constants::match_default);

regex_iterator(const regex_iterator&);
regex_iterator& operator=(const regex_iterator&);

bool operator==(const regex_iterator& right) const;
bool operator!=(const regex_iterator& right) const;
const value_type& operator*() const;
const value_type* operator->() const;
regex_iterator& operator++();
regex_iterator operator++(int);
		

 コンストラクタには2種類あります。引数がないほうのコンストラクタで作られたインスタンスは、最初からend-of-sequence iteratorになります。

 もう一つのほうは、検索対象文字列の最初を第1引数として、最後+1を第2引数として受け取り(つまり[begin, end))、第3引数以下で正規表現オブジェクトとマッチフラグとを受け取ります。こちらのコンストラクタによって作られたインスタンスが、前述のマッチする箇所を渡り歩くiteratorとして機能します。
 このiteratorは検索対象文字列内にマッチする部分があるうちは、end-of-sequence iteratorとの比較がfalseになりますが、もうマッチする箇所がなくなるとtrueになります。

//  regex_iteratorの使用例。
srell::sregex_iterator eos;  //  End-of-Sequence.
srell::sregex_iterator iter(begin, end, re, flags);

for (; iter != eos; ++iter)
{
    //  *iterやiter->でmatch_results型インスタンスにアクセス。
}
		

 ちなみにSRELLのアーカイヴに同梱されているunicode/ucfdataout.cppでは、実際にこのregex_iteratorを利用して行の切り出しを行っています。

注意

 std::regexの仕様によると、regex_iteratorが受け取ったbasic_regex型インスタンスはiterator内部でコピーされず、単にポインタを保持する仕組みになっています。そのため次のようなことをすると、iteratorを使っているうちにアクセス違反で落ちてしまいます(経験談)。

srell::sregex_iterator iter(begin, end, srell::regex("^.*$"));
		

template <class BidirectionalIterator, class charT = typename std::iterator_traits<BidirectionalIterator>::value_type, class traits = regex_traits<charT> >
class regex_token_iterator;

 regex_iteratorはmatch_results型のインスタンスを指すiteratorであるのに対して、こちらのregex_token_iteratorは、match_results型インスタンス内のsub_match型インスタンスを指すiteratorです。

 regex_token_iteratorからは次のような型がtypedefされています。通常はこのうちのいずれかを使用します。

typedef regex_token_iterator<const char *> cregex_token_iterator;
typedef regex_token_iterator<const wchar_t *> wcregex_token_iterator;
typedef regex_token_iterator<std::string::const_iterator> sregex_token_iterator;
typedef regex_token_iterator<std::wstring::const_iterator> wsregex_token_iterator;

//  ここから下はSRELL独自のもの。
typedef regex_token_iterator<const char *,
    typename std::iterator_traits<const char *>::value_type,
    u8regex_traits<typename std::iterator_traits<const char *>::value_type> >
    u8ccregex_token_iterator;
typedef regex_token_iterator<std::string::const_iterator,
    typename std::iterator_traits<std::string::const_iterator>::value_type,
    u8regex_traits<typename std::iterator_traits<std::string::const_iterator>::value_type> >
    u8csregex_token_iterator;

//  char8_t対応かどうかでu8[cs]regex_token_iteratorの定義を変える。
#if defined(__cpp_char8_t)
    typedef regex_token_iterator<const char8_t *> u8cregex_token_iterator;
    typedef regex_token_iterator<std::u8string::const_iterator> u8sregex_token_iterator;
#else
    typedef u8ccregex_token_iterator u8cregex_token_iterator;
    typedef u8csregex_token_iterator u8sregex_token_iterator;
#endif

//  C++11対応コンパイラ用。
#if defined(SRELL_CPP11_CHAR1632_ENABLED)
    typedef regex_token_iterator<const char16_t *> u16cregex_token_iterator;
    typedef regex_token_iterator<const char32_t *> u32cregex_token_iterator;
    typedef regex_token_iterator<std::u16string::const_iterator> u16sregex_token_iterator;
    typedef regex_token_iterator<std::u32string::const_iterator> u32sregex_token_iterator;
#endif

#if defined(WCHAR_MAX)
    #if WCHAR_MAX >= 0x10ffff
        typedef wcregex_token_iterator u32wcregex_token_iterator;
        typedef wsregex_token_iterator u32wsregex_token_iterator;
    #elif WCHAR_MAX >= 0xffff
        typedef regex_token_iterator<const wchar_t *,
            typename std::iterator_traits<const wchar_t *>::value_type,
            u16regex_traits<typename std::iterator_traits<const wchar_t *>::value_type> >
            u16wcregex_token_iterator;
        typedef regex_token_iterator<std::wstring::const_iterator,
            typename std::iterator_traits<std::wstring::const_iterator>::value_type,
            u16regex_traits<typename std::iterator_traits<std::wstring::const_iterator>::value_type> >
            u16wsregex_token_iterator;
    #endif
#endif
		

 regex_token_iteratorクラスのメンバは次の通りです。

typedef basic_regex<charT, traits> regex_type;
typedef sub_match<BidirectionalIterator> value_type;
typedef std::ptrdiff_t difference_type;
typedef const value_type* pointer;
typedef const value_type& reference;
typedef std::forward_iterator_tag iterator_category;

regex_token_iterator();

regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b,
    const regex_type& re,
    int submatch = 0,
    regex_constants::match_flag_type m = regex_constants::match_default
);

regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b,
    const regex_type& re,
    const std::vector<int>& submatches,
    regex_constants::match_flag_type m = regex_constants::match_default
);

//  For C++11.
regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b,
    const regex_type& re,
    std::initializer_list<int> submatches,
    regex_constants::match_flag_type m = regex_constants::match_default
);

template <std::size_t N>
regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b,
    const regex_type& re,
    const int (&submatches)[N],
    regex_constants::match_flag_type m = regex_constants::match_default
);

regex_token_iterator(const regex_token_iterator&);
regex_token_iterator& operator=(const regex_token_iterator&);

bool operator==(const regex_token_iterator&);
bool operator!=(const regex_token_iterator&);
const value_type& operator*();
const value_type* operator->();
regex_token_iterator& operator++();
regex_token_iterator operator++(int);
		

 引数のないコンストラクタでend-of-sequence iteratorを作り、それとの比較が != である間は有効という仕組みもregex_iteratorの場合と同じです。

 唯一違うのは、引数ありのほうのコンストラクタが第4引数としてint型の配列を受け取ることです。例えばこの配列に { 2, 0, 1 } という順番で数値が収められていたとすると、作成された直後のregex_token_iterator型インスタンスiterは、最初にマッチした箇所のm[2] (mはiterが内部に保持するmatch_results型のインスタンス)を指し、以後++iterするたびにポイント先がm[0], m[1]へと、配列で指定された順番通りに渡り歩いてゆきます。そこからさらに++iterすると、今度は次にマッチした箇所のm[2]を指します。
 また配列の中に-1があると、その順番の時には「前回マッチした箇所の次から今回マッチした箇所の手前まで(m.prefix()に相当)」を指すようになります。さらに最後にマッチした箇所の最後のsub_matchを指した後、end-of-sequenceへと移行する直前に、「最後にマッチした箇所の次から文字列の終わりまで(m.suffix()に相当)」を指す段階が追加されます。

{ 2, 0, 1 }の時にiterが指す順番
対象文字列 マッチ1箇所目 マッチ2箇所目
match_results
&m = *iter;
1回目の
m.prefix()
m[0] m[1] m[2] 2回目の
m.prefix()
m[0] m[1] m[2] 2回目の
m.suffix()
順番 - 1 2 0 - 4 5 3 -
{ 2, 0, -1, 1 }の時にiterが指す順番
対象文字列 マッチ1箇所目 マッチ2箇所目
match_results
&m = *iter;
1回目の
m.prefix()
m[0] m[1] m[2] 2回目の
m.prefix()
m[0] m[1] m[2] 2回目の
m.suffix()
順番 2 1 3 0 6 5 7 4 8

 -1指定は正規表現によって文字列を分割(いわゆるsplit)する時などに便利です。一例を示します。

//  正規表現によるsplit処理の例。
//  "abcd01efgh23ijklmn45opqrst67uvwx89yz".split(/\d+/) に相当することを行う。

int main()
{
    const std::string str = "abcd01efgh23ijklmn45opqrst67uvwx89yz";
    const srell::regex re("\\d+");
    const int submatches[] = { -1 };    //  マッチする箇所以外を出力する。
    srell::sregex_token_iterator it(str.begin(), str.end(), re, submatches), eoi;

    for (; it != eoi; ++it)
    {
        //  printfを使うなら。
        const std::string res(it->first, it->second);
        std::printf("result: %s\n", res.c_str());

        //  iostreamを使うなら。
        std::cout << "result: " << *it << std::endl;
    }
    return 0;
}

実行結果:
result: abcd
result: efgh
result: ijklmn
result: opqrst
result: uvwx
result: yz