PHP でテキスト ファイルのディレクトリを検索し、文字列が出現するすべてのインスタンスを一覧表示したいと考えています。
Linuxでは、これを使用します:
egrep Cheese textfile_*.txt
最初にすべてを配列に追加するという複雑さなしにこれを実行できる関数が PHP にありますか?
任意の数の任意のサイズのファイル内の任意の長さの文字列に一致するソリューションが必要であり、システム リソースが限られていると仮定します。これは最も可能性の高いシナリオであり、最もトリッキーでもあります。
すべてのファイルを単純にメモリにロードして、ファイルごとに 1 つの大きな文字列として検索することはできません。これは、メモリを大量に消費し、実際には機能の複雑さの点で特に効率的ではないためです (すべてのファイルをループし、メモリにロードしてからループします)。もう一度コンテンツを検索します)。
実際、ファイル全体をメモリにロードすることはまったく避けたほうがよいでしょう。ファイルの 1 つが 10GB の場合はどうでしょうか。
したがって、まず、ディレクトリ内のファイルのリストを取得する必要があります。これにはいくつかのアプローチがあります-glob()
何度か言及されています-しかし、このアルゴリズムの最良のアプローチは、リスト全体を配列にロードするのではなく、エントリを順番に読み取り、一度に1つずつ処理することです。これは、PHP ではopendir()
、関数のファミリーまたはDirectoryIterator
反復子クラスのファミリーのいずれかが必要であることを意味します。多くの人は、最新の PHP では後者が「正しい」方法であると主張します。
これで、ディレクトリ内のファイルのリストにアクセスできるようになりました。コンテンツにアクセスする必要があり、ファイル全体をメモリにロードせずにアクセスする必要があります。PHP ではfopen()
、(これはテキスト ファイルであるため) andが必要になることを意味しますfgets()
。これにより、一度に 1 行ずつファイルを処理できるため、複数行分のデータを一度にメモリにロードすることはありません。また、行の行の最大長を指定できる引数もあります。これは、何らかの理由でテキスト ファイルに改行がほとんどまたはまったく含まれていない場合に使用する必要があります。
つまり、ファイルをチャンクで処理しています。strpos()
検索文字列の各チャンクだけを処理できますよね? よくほとんど。検索文字列が 2 つ (またはそれ以上) のチャンクの境界を越えるとどうなりますか? ここからが面白くなり始め、より複雑な文字列検索アルゴリズムを検討する価値が生まれ始めます ( Boyer-Mooreアルゴリズムの変形は、おそらくここで役に立ちます)。
ここで決定しなければならないことは、一致をどの程度具体的にするかだけです。大文字と小文字を区別しますか? 空白の違いを許しますか? 文字セットを正規化しますか? これらは、文字列検索アルゴリズムを実装する前に、回答して説明する必要がある質問です。
状況の現実は、これらの複雑さのいくつかは、PHP で解決するのが比較的遅くなるということです。たとえば、C では非常に高速にできる文字列を一度に 1 文字ずつ反復処理する場合、 PHP では、実際のパフォーマンス キラーになります。
...この複雑さは必要ないかもしれません。少数の非常に小さなファイルを常に処理することがわかっている場合は、単純にstrpos(file_get_contents())
組み合わせアプローチを実行するだけで問題ない可能性が高くなります。検索操作が必要になる可能性があります。
本質的に、これをどのように実装するかは、作業している環境に関するいくつかの要因に依存しますが、このようなものはリソース消費の点で非常に危険である可能性があり、コードが現在および将来どのように機能する必要があるかを事前に検討する必要があります正しいソリューションを構築できます。
グロブ関数を使用します。
$text_files = glob('directory/*.txt');
foreach($text_files as $text_file) {
if (strpos('Cheese', file_get_contents($text_file)) !== false) {
echo 'File ', $text_file, ' contains "Cheese"<br>';
}
}