C++の基礎 - 正規表現

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
ナビゲーションに移動 検索に移動

概要

C++において、正規表現はテキストパターンのマッチング、検索、置換等を行うための強力なツールである。
C++ 11以降では、標準ライブラリとして<regex>ヘッダが導入されており、正規表現の機能が言語に組み込まれた。

これにより、外部ライブラリに頼ることなく正規表現を扱うことができる。

基本的な使用方法としては、std::regexクラスでパターンを定義して、std::regex_matchstd::regex_search等のメソッドを使用してマッチングを行う。
マッチした結果は、std::smatchクラスで取得できる。

正規表現の構文は、基本的に他の言語やツールで使用されているものと似ているが、いくつか特徴がある。
例えば、文字列リテラルで使用する場合はバックスラッシュを二重に記述する必要がある。
これは、C++の文字列エスケープシーケンスの仕様によるものである。

パターンマッチングのスタイルは複数用意されており、ECMAScriptスタイル (デフォルト)、basic、extended、awk等から選択できる。
最も一般的に使用されるのはECMAScriptスタイルであり、JavaScriptの正規表現と互換性がある。

また、正規表現操作にはいくつかのフラグを設定することができる。
大文字小文字を区別しない検索、複数行モード、より効率的なマッチングのための最適化等を指定できる。

エラーハンドリングも重要な要素である。
不正な正規表現パターンを指定した場合、std::regex_errorという例外が投げられるため、try-catchブロックでの適切な例外処理が推奨される。

C++の正規表現は他の言語と比べて実行速度が遅いことがある。
パフォーマンスが重要な場合は、Boostライブラリの正規表現機能や他の文字列処理手法の使用を検討する。


正規表現の使用例 : メールアドレス

以下の例では、ユーザ名、@記号、ドメイン部分を適切にパターンマッチングしている。

 #include <iostream>
 #include <regex>
 #include <string>
 
 void emailValidation()
 {
    try {
       std::string email = "user@example.com";
       std::regex pattern(R"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})");
 
       if (std::regex_match(email, pattern)) {
          std::cout << "Valid email address\n";
       }
    }
    catch (const std::regex_error &e) {
       std::cerr << "Regex error: " << e.what() << "\nCode: " << e.code() << '\n';
    }
    catch (const std::exception &e) {
       std::cerr << "Error: " << e.what() << '\n';
    }
 }
 
 int main()
 {
    try {
       emailValidation();
    }
    catch (const std::exception &e) {
       std::cerr << "Main function error: " << e.what() << '\n';
       return -1;
    }
 
    return 0;
 }



正規表現の使用例 : 電話番号

以下の例では、国内の一般的な電話番号形式に対応するパターンを使用している。

 #include <iostream>
 #include <regex>
 #include <string>
 
 void phoneNumberFormat()
 {
    try {
       std::string phone = "090-1234-5678";
       std::regex pattern(R"(\d{2,4}-\d{2,4}-\d{4})");
       std::smatch matches;
 
       if (std::regex_match(phone, matches, pattern)) {
          std::cout << "Valid phone number" << std::endl ;
          for (const auto &match : matches) {
             std::cout << match << std::endl;
          }
       }
    }
    catch (const std::regex_error &e) {
       std::cerr << "Regex error: " << e.what() << std::endl;
       std::cerr << "Code: " << e.code() << std::endl;
 
       switch (e.code()) {
          case std::regex_constants::error_collate:
             std::cerr << "Invalid collation element request" << std::endl;
             break;
          case std::regex_constants::error_ctype:
             std::cerr << "Invalid character class" << std::endl;
             break;
          case std::regex_constants::error_escape:
             std::cerr << "Invalid escape character or trailing escape" << std::endl;
             break;
          case std::regex_constants::error_backref:
             std::cerr << "Invalid back reference" << std::endl;
             break;
          case std::regex_constants::error_brack:
             std::cerr << "Mismatched brackets" << std::endl;
             break;
          case std::regex_constants::error_paren:
             std::cerr << "Mismatched parentheses" << std::endl;
             break;
          case std::regex_constants::error_brace:
             std::cerr << "Mismatched braces" << std::endl;
             break;
          case std::regex_constants::error_badbrace:
             std::cerr << "Invalid range inside braces" << std::endl;
             break;
          case std::regex_constants::error_range:
             std::cerr << "Invalid character range" << std::endl;
             break;
          case std::regex_constants::error_space:
             std::cerr << "Insufficient memory" << std::endl;
             break;
          case std::regex_constants::error_badrepeat:
             std::cerr << "Invalid repeat expression" << std::endl;
             break;
          case std::regex_constants::error_complexity:
             std::cerr << "Operation too complex" << std::endl;
             break;
          case std::regex_constants::error_stack:
             std::cerr << "Stack space overflow" << std::endl;
             break;
          default:
             std::cerr << "Unknown regex error" << std::endl;
             break;
       }
    }
    catch (const std::exception &e) {
       std::cerr << "Error: " << e.what() << std::endl;
    }
 }
 
 int main()
 {
    try {
       phoneNumberFormat();
    }
    catch (const std::exception &e) {
       std::cerr << "Main function error: " << e.what() << std::endl;
       return -1;
    }
 
    return 0;
 }



正規表現の使用例 : HTMLタグ

以下の例では、開始タグと終了タグの対応を確認しながら、HTMLタグの内容を抽出している。

 #include <iostream>
 #include <regex>
 #include <string>
 
 void htmlTagExtraction()
 {
    try {
       std::string html = "<div>Content</div><p>Paragraph</p>";
       std::regex pattern("<([a-zA-Z0-9]+)>([^<]+)</\\1>");
       std::smatch matches;
       std::string::const_iterator searchStart(html.cbegin());
 
       while (std::regex_search(searchStart, html.cend(), matches, pattern)) {
          std::cout << "Tag: " << matches[1] << ", Content: " << matches[2] << std::endl;
          searchStart = matches.suffix().first;
       }
    }
    catch (const std::regex_error &e) {
       std::cerr << "Regex error: " << e.what() << std::endl;
       std::cerr << "Code: " << e.code() << std::endl;
    }
    catch (const std::out_of_range &e) {
       std::cerr << "Out of range error: " << e.what() << std::endl;
    }
    catch (const std::exception &e) {
       std::cerr << "Error: " << e.what() << std::endl;
    }
 }
 
 int main()
 {
    try {
       htmlTagExtraction();
    }
    catch (const std::exception &e) {
       std::cerr << "Main function error: " << e.what() << std::endl;
       return -1;
    }
 
    return 0;
 }