2013.05.28
yna

強化されたPerl正規表現(perl 5.10以降)

膨大なテキストから特定のパターンを抜き出すのに便利なのが正規表現です。
正規表現は元々はgrepというツールでサポートされていた機能ですが、perlやawkといったunix発祥のスクリプト言語に採用されてから、最近では殆どの言語に、言語機能やライブラリとしてサポートされています。

正規表現はかなり強力な機能ですが、ちょっと不得意なものがあります。入れ子構造に対応できないという弱点がありました。
たとえばソースコード中からある関数の呼び出しを探し出して、特定のパラメータをチェックしたりします。

関数名(パラメータ….)

関数呼び出しは上記のような形をしていますので、func\([^)]*\)というような形で検索すると検索できそうです。

    while( $buff =~ m/CreateWindow\([^)]*\)/mgx ){
        say $&;
    }

実行してみるとわかるのですが、パラメータに括弧が含まれていると、パラメータのところの閉じ括弧でマッチしてしまって、パラメータのすべてを検索できません。

CreateWindow(
        wc.lpszClassName,      // ウィンドウクラス名
        _T("Sample Program")                       #後ろが検索されない

CreateWindow(
            _T("BUTTON")


 perl 5.10からサポートされた再帰を使用するとこのようなネストを含むようなパターンも検索できます。

    while( $buff =~ m/CreateWindow(\((?:(?>[^\(\)]+)|(?1))* \))/mgx ){
        say $&;
    }


実行するとこんな感じで、検索してきます。

CreateWindow(
        wc.lpszClassName,      // ウィンドウクラス名
        _T("Sample Program"),  // タイトルバーに表示する文字列
        WS_OVERLAPPEDWINDOW,   // ウィンドウの種類
        WINDOW_X,              // ウィンドウを表示する位置(X座標)
        WINDOW_Y,              // ウィンドウを表示する位置(Y座標)
        WINDOW_WIDTH,          // ウィンドウの幅
        WINDOW_HEIGHT,         // ウィンドウの高さ
        NULL,                  // 親ウィンドウのウィンドウハンドル
        NULL,                  // メニューハンドル
        hInst,                 // インスタンスハンドル
        NULL                   // その他の作成データ
    )
CreateWindow(
            _T("BUTTON"),                            // ウィンドウクラス名
            _T("OK"),                                // キャプション
            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,   // スタイル指定
            20, 20,                                  // 座標
            60, 40,                                  // サイズ
            hWnd,                                    // 親ウィンドウのハンドル
            NULL,                                    // メニューハンドル
            g_hInst,                                 // インスタンスハンドル
            NULL                                     // その他の作成データ
        )

少し詳しくパターンを解析します。

    while( $buff =~ m/CreateWindow
        (                               #   正規表現グループ1の開始
            \(                          #   括弧の開始
            (?:                         #   グループ化(正規表現補足なし)
                (?>[^\(\)]+)            #   括弧以外のパターン
                |                       #   OR
                (?1)                    #   正規表現グループ1へ再帰
            )*                          #   0個以上
            \)                          #   括弧の終了
        )/mgx ){                        #   正規表現グループ1の終了
        say $&;
    }

新しい正規表現のマニュアルは、こちらです。

yna

一覧に戻る