SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

標準C++の正規表現: <regex>


  • X ポスト
  • このエントリーをはてなブックマークに追加

検索:regex_search<>

 regex_matchが完全マッチするかを判定するのに対し、regex_searchはマッチ範囲を探し出してくれます。検索結果はregex_matchと同じく、match_results<>に得られます(マッチ範囲が見つからないときはfalseを返します)。

list-04
#include <iostream>
#include <regex>
#include <string>
#include <locale>

using namespace std;

int main() {
  wcout.imbue(locale("japanese"));
  const wstring input = L"すもももももももものうち";
  const wstring pattern = L"(.)ももの"; // 任意の一文字+'ももの'
  wregex re(pattern);
  wsmatch match; // match_results<wstring::const_iterator>
  if ( regex_search(input, match, re) ) {
      // str,position,length は引数省略時 0(全体マッチ)とみなす
      wcout << match.str()
            << L" pos= " << match.position()
            << L" size= " << match.length()
            << endl;
  }
}

/* 実行結果
もももの pos= 6 size= 4
*/

 regex_search関数はregex_matchと同じく、照合文字列で3種×match_resultsの有無で6通りあります。

置換:regex_replace<>

 正規表現にマッチする範囲を別の文字列に置き換えます。

list-05
#include <iostream>
#include <regex>
#include <string>
#include <locale>

using namespace std;

int main() {
  wcout.imbue(locale("japanese"));
  const wchar_t* input = L"すもももももももものうち";
  const wchar_t* pattern = L"(.)もも"; // 任意の一文字+'もも'
  const wchar_t* fmt = L"$1うどん"; // 第1sub_match + 'もも'
  wregex re(pattern);
  ostream_iterator<wchar_t,wchar_t> out(wcout);
  regex_replace(out, input, input+wcslen(input), re, fmt);
  wcout << endl;
}

/* 実行結果
すうどんもうどんもうどんのうち
*/

 この例は任意の一文字+'もも'を任意の一文字+'うどん'に置換するので、"すもももももももものうち"が"すうどんもうどんもうどんのうち"です。置換フォーマットに現れる$0, $1, ...はn番目のsub_matchに置換されます。置換フォーマットのルールは以下のとおり。

$$ → $
$& → マッチ部分
$' → 先頭からマッチ部分の直前まで
$` → マッチ部分の直後から末尾まで
$n → 第n sub_match (nは0~9)

 regen_replace関数は、

  • イテレータの組を入力し、置換結果をイテレータに出力
  • bast_string<charT>を入力し、basic_string<charT>を返す
  • const charT*を入力し、basic_string<charT>を返す

のそれぞれに対し、置換フォーマットの型: bast_string<charT> / const charT*で6通りあります。

 regex_replaceは与えた正規表現が入力文字列中に何度も現れるとき、それぞれのマッチ部分に対して置換を行います。最初のマッチ部分だけを置換したいときは引数にregex_constants::format_first_onlyを与えてください。

list-06
#include <iostream>
#include <regex>
#include <string>
#include <locale>

using namespace std;

int main() {
  wcout.imbue(locale("japanese"));
  const wchar_t* input = L"すもももももももものうち";
  const wchar_t* pattern = L"(.)もも"; // 任意の一文字+'もも'
  const wchar_t* fmt = L"$1うどん"; // 第1sub_match + 'もも'
  wregex re(pattern);
  // 置換は最初に見つかった一箇所だけ!
  wcout << regex_replace(input, re, fmt, regex_constants::format_first_only);
  wcout << endl;
}

/* 実行結果
すうどんもももももものうち
*/

反復検索:regex_iterator<>, regex_token_iterator<>

 regex_searchが入力文字列に対し正規表現が最初にマッチした箇所を教えてくれるのに対し、regex_iterator<>はマッチ箇所を"列挙"してくれます。

list-07
#include <iostream>
#include <regex>
#include <string>
#include <locale>

using namespace std;

int main() {
  wcout.imbue(locale("japanese"));
  const wstring input = L"すもももももももものうちだがこけももはももじゃない";
  const wstring pattern = L"(.)もも";
  wregex re(pattern);
  wsregex_token_iterator first(begin(input), end(input), re);
  wsregex_token_iterator last;
  while ( first != last ) {
    // regex_iteratorはmatch_resultsを指すイテレータとして機能する
    wcout << first->str()
          << L" pos= " << distance(input.begin(), first->first)
          << L" size= " << first->length()
          << endl;

    ++first;
  }
  wcout << endl;
}

/* 実行結果
すもも pos= 0 size= 3
ももも pos= 3 size= 3
ももも pos= 6 size= 3
けもも pos= 15 size= 3
はもも pos= 18 size= 3
*/

 regex_token_iterator<>もマッチ箇所の列挙を行いますが、正規表現の全体マッチだけでなく、'('と')'で囲んだsub_matchの列挙、さらにはこんなこともできますよ。

list-08
#include <iostream>
#include <regex>
#include <string>
#include <locale>
#include <initializer_list>

using namespace std;

int main() {
  wcout.imbue(locale("japanese"));
  const wstring input = L"ダフニスとクロエ,どんぐりと山猫,美女と野獣,麦とホップ,";
  const wstring pattern = L"([^,]*)と([^,]*),";
  wregex re(pattern);
  // 第2sub_match, 第1sub_match の順に列挙する
  wsregex_token_iterator first(begin(input), end(input), re, {2,1});
  wsregex_token_iterator last;
  while ( first != last ) {
    wcout << L'[' << first->str() << L"] ";
    ++first;
  }
  wcout << endl;
}

/* 実行結果
[クロエ] [ダフニス] [山猫] [どんぐり] [野獣] [美女] [ホップ] [麦]
*/

 regex_token_iteratorのコンストラクタにsub_match IDの列(この例では{2, 1})を与えておくと、そのID列の並びに従って列挙してくれます。

 以上、標準C++が提供してくれる正規表現ライブラリのご紹介でした。C++が生まれて四半世紀、ようやく正規表現が標準搭載されました。スクリプト言語にお株を奪われていた文字列処理ですが、これで一矢報いることができました。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

επιστημη(エピステーメー)

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/7716 2014/04/28 10:40

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング