読者です 読者をやめる 読者になる 読者になる

アールテクニカ地下ガレージ

アールテクニカ株式会社の製品開発・研究開発・日々の活動です

C++11の正規表現を使おう!

Author

中村@アールテクニカ

アールテクニカの中村です。
今回は、C++11の追加機能でも重要な機能の1つである正規表現を解説します。
C++11の正規表現は元々は、Boostという外部ライブラリだったものをC++の標準ライブラリとして取り込んだものです。
Boostのソースコードは規模が大きいためビルドに時間がかかりました。バイナリで配布もされていますがコンパイラのバージョンが合っていないと使えません。
標準ライブラリになったことで<regex>をインクルードするだけで気軽に使えるようになりました。

正規表現にマッチしているか判定する

std::regexで正規表現のパターンを定義し、std::regex_search()で検索します。std::regex_search()は正規表現にマッチした場合に1を返します。
正規表現にはいろいろ方言がありますが、C++11ではデフォルトではECMAScriptつまりJavaScript互換となっています。

以下のサンプルコードでは、文字列に数字が含まれているかを判定します。

#include <regex>

int main()
{
	std::string str = "123abc456abc789xyz0ab";
	std::regex regex(R"(\d+)"); // 数字

	if (std::regex_search(str, regex))
	{
		printf("matched!\n");
	}
	else
	{
		printf("unmatched!\n");
	}

	return 0;
}
実行結果
matched!

正規表現マッチした文字列を取得する

正規表現パターンの取得したい箇所を"("と")"で囲み、std::regex_search()の引数に、std::smatchの変数を追加します。
matchの1番目にはマッチした文字列全体が、2番目以降にはカッコで囲まれたマッチした箇所が1つずつ入ります。

#include <regex>

int main()
{
	std::string str = "123abc456abc789xyz0ab";
	std::regex regex(R"((\d+))"); 
	std::smatch match;

	if (std::regex_search(str, match, regex))
	{
		printf("matched!\n");
		for (auto m : match)
		{
			printf(m.str().c_str());
			printf("\n");
		}
	}
	else
	{
		printf("unmatched!\n");
	}

	return 0;
}

このの例では、カッコで囲まれた箇所が1つだったため、マッチ全体と個別のマッチが同じになります。

実行結果
123
123

正規表現マッチした文字列をすべて取得する

先ほどの例では、最初にマッチした箇所しか取得できませんでした。JavaScriptなら/\d/gの様に正規表現にgをつければすべてのマッチした箇所を取得できますが、C++11の正規表現にはその様な機能は無いようです。
検索対象文字列の先頭をマッチした箇所の分だけずらし、繰り返し正規表現による検索を実行する必要があります。
注意したいのが、str.cbegin()とstr.cend()のところです。ネット上のサンプル(VC2012?)ではそれぞれ、str.begin()とstr.end()となっていましたが、VC 2015ではエラーになってしまいました。VC2013から、std::regex_search()の引数がconst_iteratorで無くてはならないようになったようです。

int main()
{
	std::string str = "123abc456abc789xyz0ab";
	std::regex regex(R"((\d+))");
	std::smatch match;
	
	auto it = str.cbegin();
	while (std::regex_search(it, str.cend(), match, regex))
	{
		// i==0の全体マッチはスキップする
		for (int i = 1; i < match.size(); ++i)
		{
			printf(match.str(i).c_str());
			printf("\n");
		}

		// マッチした位置+長さ分イテレータをずらす
		it += match.position(0) + match.length(0); 
	}
	return 0;
}


これですべての数字部分が抽出できました。
実行結果

123
456
789
0


C++11の正規表現は、他の言語より多少使い難い点もありますが、正規表現が使えればテキスト処理は格段に楽になるので使い方をマスターしましょう!


Author

中村@アールテクニカ

アールテクニカのSE兼プログラマ。Web系のサーバサイド・フロントエンドからスマホ・PCのネイティブアプリまでソフトウェア開発全般が守備範囲。最近はハードウェア開発にも興味あり。

スポンサーリンク