PHP
 Computer >> コンピューター >  >> プログラミング >> PHP

PHPのRegexIteratorの使い方を徹底解説!正規表現でファイルをフィルタリングする方法

PHPのRegexIteratorは、イテレータから取得した要素を正規表現でフィルタリングできる便利なSPLクラスです。再帰的なディレクトリ走査と組み合わせることで、特定のパターンに一致するファイルだけを効率的に抽出できます。

この記事では、RegexIteratorの基本的な使い方から、独自のフィルタークラスを作成する応用テクニック、スキャン深度の制限方法まで、実用的なコード例とともに解説します。

正規表現でファイルを抽出する基本形

まずは、RegexIteratorを直接使って、ディレクトリ内のPHPファイルとHTMLファイルを再帰的に検索するシンプルな例を見てみましょう。

$directory = new RecursiveDirectoryIterator(__DIR__);
$flattened = new RecursiveIteratorIterator($directory);

// パスに「/.Trash*」フォルダが含まれず、拡張子が.phpまたは.htmlであることを確認
$files = new RegexIterator($flattened, '#^(?:[A-Z]:)?(?:/(?!\.Trash)[^/]+)+/[^/]+\.(?:php|html)$#Di');
foreach($files as $file) {
    echo $file . PHP_EOL;
}

このコードでは、RecursiveDirectoryIteratorでカレントディレクトリを走査し、RecursiveIteratorIteratorで平坦化しています。その後、RegexIteratorに渡す正規表現によって、次の条件を満たすパスのみが通過します。

  • パスの中に「.Trash」で始まるフォルダ(ゴミ箱など)が含まれていないこと
  • ファイル名の末尾が「.php」または「.html」であること

また、正規表現のiフラグにより大文字と小文字を区別せず、Dフラグにより$が文字列の末尾に厳密に一致するようになります。

フィルタークラスを作成する応用テクニック

より柔軟なフィルタリングを行いたい場合は、正規表現を保持する基底クラスを定義し、それを継承したフィルタークラスを作成する方法が有効です。ここではRecursiveRegexIteratorを拡張します。

基底クラスの定義

abstract class FilesystemRegexFilter extends RecursiveRegexIterator {
    protected $regex;
    public function __construct(RecursiveIterator $it, $regex) {
        $this->regex = $regex;
        parent::__construct($it, $regex);
    }
}

この抽象クラスは、フィルターで使用する正規表現を保持する役割を担います。

ファイル名・ディレクトリ名フィルターの実装

次に、基底クラスを継承して、それぞれファイル名とディレクトリ名に対して動作する基本的なフィルターを作成します。

class FilenameFilter extends FilesystemRegexFilter {
    // 正規表現を使ってファイルをフィルタリング
    public function accept() {
        return ( ! $this->isFile() || preg_match($this->regex, $this->getFilename()));
    }
}
class DirnameFilter extends FilesystemRegexFilter {
    // 正規表現を使ってディレクトリをフィルタリング
    public function accept() {
        return ( ! $this->isDir() || preg_match($this->regex, $this->getFilename()));
    }
}

accept()メソッドは、その要素が反復処理の対象として受け入れられるかどうかを判定します。ファイルでない場合やディレクトリでない場合は無条件にtrueを返し、対象となる場合のみ正規表現とのマッチング結果を返します。

フィルターを組み合わせた実際の使用例

以下のコードは、ディレクトリの内容を再帰的に走査しながら、「.Trash」フォルダを除外し、PHPファイルとHTMLファイルだけを残す例です。

$directory = new RecursiveDirectoryIterator(__DIR__);

// 「.Trash*」フォルダを除外
$filter = new DirnameFilter($directory, '/^(?!\.Trash)/');

// PHP/HTMLファイルのみを許可
$filter = new FilenameFilter($filter, '/\.(?:php|html)$/');

foreach(new RecursiveIteratorIterator($filter) as $file) {
    echo $file . PHP_EOL;
}

ポイントは、DirnameFilterの出力をそのままFilenameFilterの入力として渡している点です。このようにフィルターを連結(チェーン)することで、複数の条件を段階的に適用できます。ネガティブ先読み(?!\.Trash)により、「.Trash」で始まるディレクトリが除外されます。

スキャンする深さを制限する方法

上記のコードに少し手を加えることで、指定した階層数までだけスキャンすることも可能です。setMaxDepth()メソッドを使用します。

$files = new RecursiveIteratorIterator($filter);
$files->setMaxDepth(1); // 2階層分。引数は0始まり。
foreach($files as $file) {
    echo $file . PHP_EOL;
}

setMaxDepth()の引数は0から始まるため、1を指定すると2階層目までが走査されます。デフォルト値は-1で、これは深さ無制限を意味します。

まとめ

RegexIteratorを使えば、正規表現による強力なフィルタリングをSPLイテレータの仕組みに自然に組み込めます。単純な用途ではRegexIteratorを直接使うだけで十分ですが、ファイル名とディレクトリ名に異なる条件を適用したい場合は、RecursiveRegexIteratorを継承した独自フィルタークラスを作成すると、コードの再利用性と保守性が大きく向上します。

  1. Android ViewPagerの使い方を徹底解説!TabLayoutと連携したFragment切り替えの実装手順

    Android ViewPagerとは?実装例に入る前に、まずViewPagerの基本をおさえておきましょう。ViewPagerはAndroidのサポートライブラリに含まれるウィジェットの一つで、画面を左右にスワイプするだけでFragment(フラグメント)を切り替えられる便利なコンポーネントです。チュートリアル画面や画像ギャラリー、タブ式のコンテンツ切り替えなど、さまざまなアプリで活用されている定番UIです。本記事では、ViewPagerとTabLayoutを組み合わせた実装方法を、具体的なコード例とともにステップ形式で解説します。ステップ1:新規プロジェクトを作成するAndroid Stu

  2. 【Android】CheckedTextViewの使い方を徹底解説!クリック判定の実装手順

    CheckedTextViewとは?Android開発におけるCheckedTextViewは、標準のTextViewを拡張したウィジェットで、「Checkableインターフェース」を実装している点が大きな特徴です。このウィジェットを活用することで、ユーザーがテキストビューをクリック(チェック)したかどうかを簡単に判別できます。本記事では、AndroidアプリでCheckedTextViewを使用する具体的な方法を、サンプルコードとともにステップごとにわかりやすく解説します。ステップ1:新規プロジェクトを作成するまずはAndroid Studioで新しいプロジェクトを作成しましょう。メニューか