膨大なテキストから特定のパターンを抜き出すのに便利なのが正規表現です。
正規表現は元々は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