LoginSignup
16
21

More than 3 years have passed since last update.

C++で正規表現を使う

Posted at

C++で正規表現を使う方法を解説する。std::regexを使えば良いのだが、ここではあまり凝った使い方は説明せず、とりあえず最小限の手間で使い始めるまでの方法をまとめる。

参考

最小限のコード

まずは最小限動作するコードをいかに示す。

#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+))"));
16
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
21