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