C++で正規表現を使う方法を解説する。std::regex
を使えば良いのだが、ここではあまり凝った使い方は説明せず、とりあえず最小限の手間で使い始めるまでの方法をまとめる。
参考
- https://cpprefjp.github.io/reference/regex.html
- https://cpprefjp.github.io/reference/regex/regex_match.html
- https://cpprefjp.github.io/reference/regex/match_results.html
最小限のコード
まずは最小限動作するコードをいかに示す。
#include <string>
#include <regex>
int main() {
std::string s1 = "1234";
std::string s2 = "abc";
std::regex re(R"(\d+)"); // raw string literal
assert( std::regex_match(s1, re) );
assert (!std::regex_match(s2, re) );
return 0;
}
解説
- 正規表現を使うためのヘッダをインクルードする
#include <regex>
- 正規表現オブジェクトを構築する。
std::regex re(R"(\d+)");
コンストラクタの引数に正規表現を文字列で渡せばよい。R"( ... )"
という記法は見慣れないかもしれないが、これはraw string literal という記法で\
や"
などの文字に対してエスケープする必要がなくなる。正規表現ではバックスラッシュを多用するのでこのリテラルが便利。
- 正規表現がマッチするかチェックする。
std::regex_match(s1, re);
ちなみにregex_match
は文字列全体が正規表現に一致するかを判定する。部分文字列に一致するか判定する場合は regex_search
を代わりに使うと良い。
例は以下。
std::string s2 = "abc 1234";
std::regex re(R"(\d+)");
std::regex_search(s2, re); // => true
マッチした結果を参照する
正規表現にマッチした文字列を取得したい場合には以下のようなコードを書く。
std::string s = "123-4567";
std::smatch m;
if ( std::regex_match(s, m, std::regex(R"((\d+)-(\d+))")) ) {
std::cout << m[0].str() << std::endl; // => 123-4567
std::cout << m[1].str() << std::endl; // => 123
std::cout << m[2].str() << std::endl; // => 4567
}
- 正規表現によるマッチ結果を格納するコンテナ
std::smatch
変数を用意する。
std::smatch m;
ここで注意点として、判定する文字列がstd::string
の場合にはstd::smatch
を使うが、もしchar*
だった場合 std::cmatch
型を利用しなければコンパイルエラーになる。つまり判定したい文字列の型によってマッチ結果の型が異なる。
ここで宣言したm
という変数は実際にはstd::regex_match
または std::regex_search
が呼ばれるまでは、ほとんどのメソッドを利用することができない(空の結果が返ってくる)。参照して何か意味がある結果が得られるのは、これらのメソッドが呼ばれた後になる。
- マッチした文字列を取得する
m[0].str() // 123-4567
m[1].str() // 123
m[2].str() // 4567
コンテナの最初の要素には、マッチした文字列全体を表すサブマッチが格納され、以降に各キャプチャグループ(正規表現内の括弧で囲まれた部分に対応する)が続く。
ここで返る値はsub_match
オブジェクトである。.str()
を呼ぶと文字列が得られる。
(https://cpprefjp.github.io/reference/regex/match_results/op_at.html)
注意点として、マッチ結果オブジェクトm
は検索対象文字列s
へのイテレータを保持する。
このため、検索対象文字列はregex_match
またはregex_search
を呼び出した後も match_results オブジェクトを使用し終わるまで破棄されないようにする必要がある。
例えば次のようにregex_search
の引数に一時オブジェクトを指定することはほぼ間違いなくプログラミング上のエラーを意味する。(このコードはC++14ではコンパイルエラー。C++11ではコンパイルできるが、結果は未定義)
std::smatch m;
std::regex_match(std::string("123-4567"), m, std::regex(R"((\d+)-(\d+))"));