劣等コンプレックス500%

身動きとれねえ 絵・プログラミング(C/C++/Java/Perl/PHP/Mysql)

【C/C++】 C++でPerlの正規表現のループwhile(/~/g){}を実装してみた。

標準C++ライブラリでの正規表現
Perlの繰り返しマッチwhile(/~/g){}を実現してみた。

VC++2010で動作確認。unicodeもマルチバイトでも動きました。cppはsjisで保存

しかしググっても情報が少なすぎる。正規表現の用途って文字列キャプチャが主じゃないの??
ということでメモって置きます

0x5Cにも問題対応。が、ワイド文字を扱うstd::wstringクラスを利用する必要がある。<Ⅸ噂浬>と<欺圭構>に囲まれた文字列を繰り返しキャプチャするコードです。
加えてマッチした位置を算出してますんでsubstr()なんかと組み合わせてアレコレできると思います。

おまけに普通の正規表現正規表現による置換処理も書いてあります。

あと、標準のregexには.(任意の1文字)に改行もマッチさせるオプションはないらしい。<Ⅸ噂浬>((?:.|\n)*?)<欺圭構>
こんなふうに書くしか無いすね



Perlの繰り返しマッチwhile(/~/g){}風

wcout << L"★ループマッチング " << endl;
wstring text = L"strstr<Ⅸ噂浬>ソソソ<欺圭構>gggg<Ⅸ噂浬>十十十<欺圭構><Ⅸ噂浬>貼貼貼<欺圭構><Ⅸ噂浬>能能能<欺圭構>";
wregex reg(L"<Ⅸ噂浬>(.*?)<欺圭構>", regex_constants::icase);

wstring::const_iterator text_iter = text.cbegin();
wsmatch results;
int idx = 0;
while(regex_search(text_iter, text.cend(), results, reg, regex_constants::match_default)){
	//括弧でキャプチャした個数が入る。マッチした文字列全体も含むので1以上になるハズ
	int count = results.size();
	for(int i = 0; i < count; i++){
		wcout << L"グループ("<<i<<"): "  << results.str(i)  << endl;
		wcout << L"マッチ文字長: " << results.length(i) << endl;
		wcout << L"マッチ位置 : " << idx + results.position(i) << endl;
		wcout << "" << endl;
	}
	idx = results[0].second - text.cbegin();
	text_iter = results[0].second;
}


・全体ソースコード

#include <regex>
#include <iostream>
#pragma comment(lib,"libcpmtd.lib")

using namespace std;

int _tmain(int argc, _TCHAR* argv[]){
	wcout.imbue(locale("japanese"));
	try {
		wcout << L"★ループマッチング " << endl;

		wstring text = L"strstr<Ⅸ噂浬>ソソソ<欺圭構>gggg<Ⅸ噂浬>十十十<欺圭構><Ⅸ噂浬>貼貼貼<欺圭構><Ⅸ噂浬>能能能<欺圭構>";
		wregex reg(L"<Ⅸ噂浬>(.*?)<欺圭構>", regex_constants::icase);

		wstring::const_iterator text_iter = text.cbegin();
		wsmatch results;
		int idx = 0;
		while(regex_search(text_iter, text.cend(), results, reg, regex_constants::match_default)){
			//括弧でキャプチャした個数が入る。マッチした文字列全体も含むので1以上になるハズ
			int count = results.size();
			for(int i = 0; i < count; i++){
				wcout << L"グループ("<<i<<"): "  << results.str(i)  << endl;
				wcout << L"マッチ文字長: " << results.length(i) << endl;
				wcout << L"マッチ位置 : " << idx + results.position(i) << endl;
				wcout << "" << endl;
			}
			idx = results[0].second - text.cbegin();
			text_iter = results[0].second;
		}

		//おまけ。1回のみの正規表現マッチング。
		// regex_match()を使う。
		//
		{	
			wcout << L"★一回マッチング " << endl;

			wstring text = L"<Ⅸ噂浬>HOGE255<欺圭構>";
			//regex_constants::icaseオプションで大小区別なし。
			wregex reg(L"<Ⅸ噂浬>(hoge)(\\d+)<欺圭構>", regex_constants::icase);
			wsmatch results;

			 if(regex_match(text, results, reg)){
				 wcout << L"マッチ! " << endl;

				 wcout << L"グループ(1): "  << results.str(1)  << endl;
				 wcout << L"グループ(2): "  << results.str(2)  << endl;
			 }
		}
		//おまけ2。正規表現による文字列置換
		{	
			wcout << L"★文字列置換" << endl;

			wstring text = L"<123/456>ソソソ<123/456>十十十<123/456>";
			wregex  reg(L"<(123)/(456)>");
			wstring replace = L"[$2-$1]"; 
	
			wcout << regex_replace(text, reg, replace) << endl;
			wcout << regex_replace(text, wregex(L"<(123)/(456)>"), wstring(L"[$2-$1]")) << endl;
		}
	} catch (regex_error &e) {
		cout << "what: " << e.what() << "; code: " << e.code() << endl;
	}

	getchar();
	return 0;
}

・結果
f:id:magicu:20170116001138j:plain