''[[FrontPage]]''
* C++と正規表現(regex++) テストその3(最終) [#u0885174]
C/C++言語ソースファイルを想定し、正規表現を使って解析する。~
~
&color(#FF0000,){とりあえずC++正規表現シリーズはこれで凍結とします。};~
&color(#FF0000,){ここまでできれば、あとは自分で検索対象を追加実装するなり、出力まわりを変更したりはできるはずです。};

[[C++入門/正規表現1]]~
[[C++入門/正規表現2]]

** 制約 [#bc40674b]
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からの分も含む) [#u5fb6e49]
boost、regexライブラリのビルドに成功。~
Unicodeへの対応は強引だが可能?(なにがおもしろいのかがいまいち分からない)

*** 課題 [#a8b2c7cf]
インクルードファイル名が"xxxx.h.h"のように、複数のピリオドを含んでいたら?(打開済)~
defineによる定数定義が、文字定数や文字列によって行われていたら?(打開不可能?)
 #define CHAR_THREE '3'       // 文字定数なら打開可能
 #define COMMENT "// comment" // コメント削除対象になってしまう。
  → ここまではさすがに対応しなくても良さそうな気がする。~
~
今はcoutで画面表示に成功しているが、UNICODE対応(wsmatch使用)にすると、コンパイルエラーとなる。(打開済)~
むしろ、sub_matchが文字列として表示されていることが奇跡的?(打開済)~
 string( partial[0].first, partial[0].second).c_str() )    // マッチ開始ポイントと終了ポイントを利用してstring型を作る。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS