[c++11] std::regex のメモ

#include <iostream>
#include <regex>
#include <sstream>

void RegexSample()
{
  // 正規表現 std::regex, std::wregex

  //
  // regex_match で正規表現に一致するかどうかの判定
  //
  puts("************************");
  {
    std::regex re("^a[bc]+d$");
    bool matched = std::regex_match("abccbbbd", re); // true
    puts(matched ? "true" : ""); // true

    // 文字列全体が一致していないとNG
    matched = std::regex_match("abcde", re);
    puts(matched ? "" : "false"); // false
  }

  //
  // regex_matchでマッチした部分やキャプチャの取得
  //
  puts("************************");
  {
    // ignore case なオプション指定
    std::regex re("a(bc)d(e)", std::regex_constants::icase);

    // cmatch = std::match_results<const char *>
    std::cmatch match;

    // regex_match の第2引数に match を指定
    if (std::regex_match("ABCDE", match, re) || true)
    {
      printf("size:%ld \n", match.size()); // 2

      // サブマッチ(キャプチャ): [0] は全体のキャプチャ
      // csub_match = std::sub_match<const char *>
      const std::csub_match &submatch0 = match[0];
      printf("match[0]      str: %s \n", submatch0.str().c_str()); // ABCDE
      printf("match[0] position: %ld\n",
             std::distance("ABCDE", submatch0.first)); // 0
      printf("match[0]    first: %s \n", submatch0.first);  // ACDE
      printf("match[0]   second: %s \n", submatch0.second); // (空文字)
      printf("match[0]   length: %ld\n", submatch0.length()); // 5

      // sizeの数で反復
      for (int i = 0; i < match.size(); i++) {
        printf("[%d]      str: %s \n", i, match.str(i).c_str());
        printf("[%d] position: %ld\n", i, match.position(i));
        printf("[%d]   length: %ld\n", i, match.length(i));
        /* 出力は以下の通り
         [0]      str: ABCDE
         [0] position: 0
         [0]   length: 5
         [1]      str: BC
         [1] position: 1
         [1]   length: 2
         [2]      str: E
         [2] position: 4
         [2]   length: 1
         */
      }

      // イテレータで反復
      for (auto it = match.begin(); it != match.end(); it++) {
        const std::csub_match &submatch = *it;
      }

      // type-based-for-loopで反復
      for (const std::csub_match &submatch : match) { }

      // std:cmatch::format でマッチした部分を文字列フォーマット
      // $9 とかキャプチャされてない部分を出力しようとするとクラッシュするので注意

      // $0:ABCDE $1:BC $2:E
      puts(match.format("$$0:$0 $$1:$1 $$2:$2").c_str());
    }
  }

  //
  // regex_replace で文字列を置換
  //
  {
    puts(std::regex_replace("a to z",
                            std::regex("(angel) to (z)"),
                            "$2 to $1").c_str()); // "z to a" と出力される
  }

  //
  // regex_search は全体ではなく一部のマッチ
  //
  puts("************************");
  {
    std::string input = "_ac=cd-";
    std::regex re("([a-z]+)", std::regex_constants::nosubs);
    std::cmatch match;
    if (std::regex_search(input.c_str(), match, re))
    {
      // sizeの数で反復
      for (int i = 0; i < match.size(); i++) {
        printf("[%d]      str: %s \n", i, match.str(i).c_str());
        printf("[%d] position: %ld\n", i, match.position(i));
        printf("[%d]   length: %ld\n", i, match.length(i));
        /* 出力は以下の通り (nosubsオプションを指定したのでsubmatch無し)
         [0]      str: ac
         [0] position: 1
         [0]   length: 2
         */
      }
    }
  }

  //
  // regex_token_iterator で マッチする部分を全て取得
  // (javascriptのgオプションみたいな…)
  // typedef regex_token_iterator<const char*>
  //     cregex_token_iterator;
  // typedef regex_token_iterator<const wchar_t*>
  //     wcregex_token_iterator;
  // typedef regex_token_iterator<string::const_iterator>
  //     sregex_token_iterator;
  // typedef regex_token_iterator<wstring::const_iterator>
  //     wsregex_token_iterator;
  //
  puts("************************");
  {
    std::string input = "abbcdddeffffg";
    std::regex re("(.)\\1\\1");
    std::sregex_token_iterator iter(std::begin(input), std::end(input), re), end;
    for (; iter != end; iter++) {
      printf("%s ", iter->str().c_str()); // "ddd fff " と出力される
    }
    puts("");
  }

  //
  // regex_search で キャプチャを含めて一致する部分を全て取得
  //
  puts("************************");
  {
    std::string input = "_ac=cd-";
    std::regex re("([a-z]+)");
    std::vector<std::smatch> matches;
    std::string::const_iterator iter = input.cbegin();
    std::smatch match; // smatch = std::match_results<string::const_iterator>
    while (std::regex_search(iter, input.cend(), match, re))
    {
      matches.push_back(match);
      iter = match[0].second; // 次の検索開始位置を指定
    }

    for (int i = 0; i < matches.size(); i++) {
      const std::smatch &match = matches[i];
      const std::ssub_match &match0 = match[0];
      printf("matches[%d]    str: %s \n", i, match0.str().c_str());
      printf("matches[%d]  first: %c \n", i, *match0.first); // firstはchar
      printf("matches[%d] second: %c \n", i, *match0.second);
      printf("matches[%d] length: %ld\n", i, match0.length());
      /* 出力は以下の通り
       matches[0]    str: ac
       matches[0]  first: a
       matches[0] second: =
       matches[0] length: 2
       matches[1]    str: cd
       matches[1]  first: c
       matches[1] second: -
       matches[1] length: 2
       */
    }
  }

  //
  // コールバック置換 (サブマッチが使えない)
  // http://stackoverflow.com/questions/22617209/regex-replace-with-callback-in-c11
  // を参考に適当な関数を作成
  //
  puts("************************");
  {
    auto regexReplace =
    [](const std::regex &re,
       const std::string &input,
       const std::function<std::string(const std::string&)> &callback)
    {
      std::string ret;
      std::sregex_token_iterator
        begin(input.begin(), input.end(), re, {-1, 0}), end;
      std::for_each(begin, end, [&ret, &re, &callback](const std::string &m)
      {
        ret += std::regex_match(m.c_str(), re) ? callback(e) : m;
      });
      return ret;
    };

    auto callback = [&](const std::string &m)
    {
      std::istringstream iss(e);
      int n;
      iss >> n;
      return std::to_string(n+1);
    };

    // "my values are 10, 20" と出力される
    printf("%s \n", regexReplace(std::regex("\\d+"),
                                 "my values are 9, 19",
                                 callback).c_str());
  }

  //
  // コールバック置換 (サブマッチあり)
  //
  puts("************************");
  {
    auto regexReplace =
    [](const std::regex &re,
       const std::string &input,
       const std::function<std::string(const std::smatch &)> &callback)
    {
      std::string ret;
      auto iter = input.cbegin();
      auto iterEnd = input.cend();
      std::smatch match;
      while (std::regex_search(iter, iterEnd, match, re))
      {
        auto iterNext = match[0].second;
        ret.append(iter, iterNext - match[0].length()); // 非マッチ部分を追加
        ret += callback(match); // マッチした部分をcallbackで置換
        iter = iterNext; // 次の検索開始位置を指定
      }
      ret.append(iter, iterEnd);
      return ret;
    };

    // "-ABCDE-" と出力される
    printf("%s \n", regexReplace(std::regex("-(.)-"),
                                 "--A--B--C--D--E--",
                                 [](const std::smatch &match)
    {
      return match[1].str();
    }).c_str())
  }
}
Share
関連記事