C++教科書/標準ライブラリ編/<regex>の章
編集はじめに
編集テキスト処理では、特定のパターンに合致する部分文字列を検索・置換することがよくあります。この際、正規表現を使うと非常に柔軟で強力な処理が可能になります。C++11で導入された<regex>
ヘッダーは、ECMAScript準拠の正規表現を提供し、パターンマッチングやテキスト変換などの機能を備えています。
正規表現クラスとその操作
編集std::basic_regexクラステンプレート
編集正規表現オブジェクトはstd::basic_regex
クラステンプレートのインスタンスで表されます。
- コンストラクタ
-
- デフォルトコンストラクタ
- 文字列から構築 (
basic_regex(str, flags)
) - 反復子の範囲から構築 (
basic_regex(first, last, flags)
)
- 代入演算子では、文字列や反復子の範囲から新しい正規表現を代入できます。
- その他のメンバー関数
-
mark_count()
- サブマッチの個数を返す
flags()
- 使用中のフラグを返す
swap()
- 別の正規表現オブジェクトと値を交換
std::regex_traits
編集文字列処理のカスタマイズを行うトレイトスクラスです。特殊な文字の扱い方を指定したり、ロケールに基づいた照合順を利用できます。
例:
std::regex_traits<char> traits; std::string name = traits.transform("ámígo", std::use_facet<std::ctype<char>>(loc));
マッチング関数
編集std::regex_match
編集与えられた文字列全体が正規表現にマッチするかをテストします。
std::string text = "Hello, World!"; std::regex re("Hello, World!"); std::smatch m; bool matched = std::regex_match(text, m, re); // matched == true
std::regex_search
編集文字列のあらゆる部分が正規表現にマッチするかを探索します。
std::string text = "Hi Hello, World! Hello?"; std::regex re("Hello"); std::smatch m; bool found = std::regex_search(text, m, re); // found == true
std::regex_replace
編集正規表現にマッチする部分を置換した新しい文字列を生成します。
std::string text = "Hello, 2023! Hello, 2024?"; std::regex re("Hello, \\d+"); std::string replaced = std::regex_replace(text, re, "Hi"); // replaced == "Hi! Hi?"
マッチ結果を表すクラス
編集std::sub_match
編集サブマッチを表現するクラスで、マッチした部分文字列の開始・終了イテレータを保持します。length()メソッドでマッチした長さを取得でき、std::stringに変換して内容を参照できます。
std::match_results
編集全体のマッチ結果を保持するコンテナクラスで、サブマッチごとにstd::sub_matchオブジェクトを格納しています。添字アクセスでサブマッチを取り出せます。さらに、prefix(), suffix()でマッチした前後の文字列を取得できます。
format()メンバー関数を使うと、マッチした部分だけを抜き出したり置換することができます。
std::string text = "My name is Jane. Her name is Jane too."; std::regex re("(\\w+)\\s*is\\s*(\\w+)"); std::smatch m; std::regex_search(text, m, re); std::ssub_match sub1 = m[1]; // "My" std::ssub_match sub2 = m[2]; // "Jane" std::string fmt = "$2 was mentioned twice: '$&'"; std::string replaced = m.format(fmt); // replaced == "Jane was mentioned twice: 'My name is Jane. Her name is Jane too.'"
イテレータクラス
編集std::regex_iterator
編集文字列中に現れるすべての正規表現マッチを走査するイテレータです。エンドイテレータに到達するまでインクリメントを続けることで、順次マッチしたsub_matchオブジェクトを取得できます。
std::string text = "Hi! Hello, World! Hello, Regex!"; std::regex re("Hello[^!]+"); std::sregex_iterator iter(text.begin(), text.end(), re); std::sregex_iterator end; for (; iter != end; ++iter) { std::cout << iter->str() << '\n'; // Hello, World!, Hello, Regex! }
std::regex_token_iterator
編集正規表現にマッチした部分だけでなく、マッチしなかった部分(トークン)も取り出せるイテレータです。-1を指定するとマッチしなかった部分を、0以上を指定するとそのインデックスのサブマッチを取得できます。
std::string text = "Hi! Hello, World! Hello, Regex!"; std::regex re("Hello[^!]+"); std::sregex_token_iterator iter(text.begin(), text.end(), re, {-1, 0}); std::sregex_token_iterator end; for (; iter != end; ++iter) { std::cout << *iter << '\n'; // Hi!, Hello, World, Hello, Regex, ! }
正規表現の構文とフラグ
編集std::regex_constants
編集<regex>
ヘッダーでは、正規表現の構文やマッチのオプションなどが、std::regex_constants
の型エイリアスとして定義されています。
syntax_option_type
- 正規表現の構文ルールを指定するフラグ
match_flag_type
- マッチングのオプション
error_type
- エラーの種類を表す列挙型
std::regex re("HELLO", std::regex::icase); // 大文字小文字を区別しない std::smatch m; std::regex_search("hello", m, re); // マッチする
例題
編集身分証番号の書式チェック:
std::regex id_regex("\\d{4}-\\d{4}-\\d{4}-\\d{2}"); std::string id = "1234-5678-9012-34"; if (std::regex_match(id, id_regex)) { std::cout << "Valid ID format\n"; }
URLからドメインを抽出:
std::regex url_regex("https?://([\\w.-]+)"); std::string url = "https://cpprefjp.github.io"; std::smatch m; if (std::regex_search(url, m, url_regex)) { std::cout << "Domain: " << m[1] << '\n'; // cpprefjp.github.io }
まとめ
編集<regex>
ヘッダーによって、C++プログラムに正規表現の機能が統合されました。正規表現は文字列処理において非常に強力なツールであり、パターンマッチングや検索、置換など様々な用途に役立ちます。
std::basic_regex
クラスでは正規表現オブジェクトを作成し、std::regex_match、std::regex_search、std::regex_replaceといった関数で文字列操作を行えます。マッチした結果はstd::match_resultsに格納され、サブマッチへのアクセスやフォーマット出力が可能です。
さらに、std::regex_iteratorやstd::regex_token_iteratorを使えば、文字列中の複数の部分文字列を反復処理できます。また、std::regex_constantsで正規表現の構文やマッチオプションをカスタマイズできます。
正規表現の適切な利用により、プログラムのコード量を削減しながら、効率的で堅牢な文字列処理を実現できます。<regex>
ヘッダーの提供する機能を理解し、上手く活用することが重要です。