FrontPage

C++と正規表現(regex++) テストその3(最終)

C/C++言語ソースファイルを想定し、正規表現を使って解析する。

とりあえずC++正規表現シリーズはこれで凍結とします。
ここまでできれば、あとは自分で検索対象を追加実装するなり、出力まわりを変更したりはできるはずです。

C++入門/正規表現1
C++入門/正規表現2

制約

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ライブラリのビルドに成功。
Unicodeへの対応は強引だが可能?(なにがおもしろいのかがいまいち分からない)

課題

インクルードファイル名が"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
Last-modified: 2010-02-08 (月) 02:08:12 (5184d)