C++と正規表現(regex++) テストその3(最終) †C/C++言語ソースファイルを想定し、正規表現を使って解析する。 制約 †MFC、.NET関数を使用しないこと。 #include <string> // #include <iostream> // for cout #include <sstream> // for ostringstream #include <boost/regex.hpp> // for regex++ #include <tchar.h> // // # include "x.x.txt" // (空)宣言文のあらゆる可能性をテスト #define MODE_ONE 1 // 解析モード1(include) #define MODE_TWO 2 // 解析モード2(define) #define MODE_THREE 3 // 解析モード3(const) #define MODE_FOUR 4 // 解析モード4(予備) #define MODE_FIVE 5 // 解析モード5(予備) //# define s_s_s s _T("// comment") // (空)宣言文のあらゆる可能性をテスト // using namespace std; // 名前空間 using namespace boost; // 名前空間 // #ifdef UNICODE // 強引に対応。単独プロジェクトならOK? typedef wregex tregex; // ま、正直どうやったら良いのか分からない。 typedef wstring tstring; // typedef wsmatch tsmatch; // //typedef wstringstream tstringstream; // //typedef wprintf tprintf; // * 出力に関しては自分で統一すべきか #else // typedef regex tregex; // typedef string tstring; // typedef smatch tsmatch; // //typedef stringstream tstringstream; // //typedef wprintf tprintf; // * 出力に関しては自分で統一すべきか #endif // // typedef unsigned char u1b; // typedef signed char s1b; // // s1b analizer( tstring de_file, u1b mode ); // プロトタイプ s1b styleRemove( tstring* de_file ); // プロトタイプ // s1b main( void ) // 正規表現のテスト(インクルード宣言を探す) { // const tstring file( // ソースファイルの内容を仮定 _T("#include <windows.h> // インクルード宣言\n") // _T("#include \"me.h.h\" \n") // _T("#include \"stuff.h\" \n") // _T("#include \"a.hpp.cpp\" // #include \"ab.h\"の代替、とかなんとか\n") // _T("/* #include \"mantarou.h\" うまく\n") // _T("いくかな?\n*/") // _T("// #include \"b.h\"\n") ); // // styleRemove( (tstring*)&file ); // コメントの削除 ** キャストがないとなぜエラー? analizer( file, MODE_ONE ); // モード1で呼び出し() // getchar(); // 表示結果確認用 return 0; // } s1b analizer( // ソースファイル解析関数 tstring de_file, // IN: 対象文字列先頭アドレス u1b mode ) // IN: 解析モード { // try // 例外処理 { // メモリ参照エラーの可能性あり? tregex target; // 検索文字列 // switch( mode ) // 解析モードで分岐 { // case MODE_ONE: // 解析モード1(include) target = // 検索文字列のコンパイル // _T("\n[[:blank:]]*") // シビアに判定する場合用(ただし1行目はヒットしない。) _T("#[[:blank:]]*(include)") // "#"と空白を挟んだ"include" _T("[[:blank:]]*L?\"") // 0以上の空白文字に続く'"' _T("(.*?)") // ファイル名を最短マッチ // _T("\\.[hc]p{0,2})") // 拡張子を指定する場合用 _T("\"" ); // ダブルクォーテーション右 break; // // case MODE_TWO: // 解析モード2(define) break; // // case MODE_THREE: // 解析モード3(const) break; // // case MODE_FOUR: // 解析モード4(予備) break; // // case MODE_FIVE: // 解析モード5(予備) break; // // default: // その他の場合 break; // } // // tstring::const_iterator start; // イテレータの宣言 tstring::const_iterator end; // イテレータの宣言 // start = de_file.begin(); // 開始イテレータの設定 end = de_file.end(); // 末尾イテレータの設定 // tsmatch partial; // マッチ情報を格納する match_flag_type flags = match_default; // flagの初期設定 // while(regex_search(start, end, partial, target, flags)) // ループ { // マッチが見つかった場合 printf( "partial[0] = %s\n", // 画面表示(マルチバイト) string( partial[0].first, partial[0].second).c_str() ); // 部分文字列[0](全体) wprintf( L"partial[1] = %s\n", // 画面表示(ワイド文字列) wstring( partial[1].first, partial[1].second).c_str() ); // 部分文字列[1] wprintf( L"partial[2] = %s\n", // 画面表示(ワイド文字列) wstring( partial[2].first, partial[2].second).c_str() ); // 部分文字列[2] wprintf( L"partial[3] = %s\n", // 画面表示(ワイド文字列) wstring( partial[3].first, partial[3].second).c_str() ); // 部分文字列[3] wprintf( L"partial[4] = %s\n\n", // 画面表示(ワイド文字列) wstring( partial[4].first, partial[4].second).c_str() ); // 部分文字列[4] // start = partial[0].second; // 開始イテレータの更新(次のマッチを探す) // flags |= match_prev_avail; // flagの更新 flags |= match_not_bob; // } // } // catch( const exception& e ) // 例外発生時処理 { // printf("解析エラー\n"); // 画面表示 return -1; // 異常終了 } // // return 0; // 処理終了 } s1b styleRemove( // コメント削除関数 tstring* de_file ) // OUT: 対象文字列先頭アドレス { // try // 例外処理 { // メモリ参照エラーの可能性あり? printf("コメント削除前のサイズ = %d\n", de_file->size() ); // 動作確認用 // tregex block( // 検索対象文字列のコンパイル(ブロックコメント) _T("/\\*") // 開始点"/*" _T(".*?") // 最短マッチ _T("\\*/") ); // 終了点"*/" // tregex line( // 検索対象文字列のコンパイル(1行コメント) _T("[[:blank:]]*") // 0以上のブランク _T("//.*?\n") ); // 続く"//"からはじめての改行まで // *de_file = regex_replace( // ブロックコメント削除(""で置換) *de_file, block, _T(""), match_default ); // *** ブロックコメントから先に消すこと! // *de_file = regex_replace( // 1行コメント削除(""で置換) *de_file, line, _T(""), match_default ); // *** なぜなら、"/**///"の並びでバグるから // printf("コメント削除後のサイズ = %d\n\n", de_file->size() ); // 動作確認用 } // catch( const exception& e ) // 例外発生時処理 { // printf("コメント削除エラー\n"); // 画面表示 return -1; // 異常終了 } // // return 0; // 正常終了 } 表示結果 コメント削除前のサイズ = 197 コメント削除後のサイズ = 88 partial[0] = #include "me.h.h" partial[1] = inlude partial[2] = me.h.h partial[3] = partial[4] = partial[0] = #include "stuff.h" partial[1] = inlude partial[2] = stuff.h partial[3] = partial[4] = partial[0] = #include "a.hpp.cpp" partial[1] = inlude partial[2] = a.hpp.cpp partial[3] = partial[4] = 修正履歴 (その2からの分も含む) †boost、regexライブラリのビルドに成功。 課題 †インクルードファイル名が"xxxx.h.h"のように、複数のピリオドを含んでいたら?(打開済) #define CHAR_THREE '3' // 文字定数なら打開可能 #define COMMENT "// comment" // コメント削除対象になってしまう。 → ここまではさすがに対応しなくても良さそうな気がする。 string( partial[0].first, partial[0].second).c_str() ) // マッチ開始ポイントと終了ポイントを利用してstring型を作る。 |