
# テキスト検索

Grephのテキストモードは、走査したファイルツリーを対象に、行単位でバイト列を検索します。これは`greph` CLIと`Greph::searchText()`ファサードのデフォルトモードです。出力には、grep、ripgrep、およびほとんどのエディター連携機能が解析できる標準の`file:line:content`形式を使用します。

## すぐに試せる例

```bash
# Regex search across the current directory
./vendor/bin/greph "function\s+\w+"

# Fixed-string search across src/
./vendor/bin/greph -F "function" src

# Case-insensitive whole-word search
./vendor/bin/greph -F -i -w "function" src

# Two lines of context around each match
./vendor/bin/greph -F -C 2 "TODO" src

# Stop after the first three matches per file
./vendor/bin/greph -F -m 3 "TODO" src

# Files that contain the pattern
./vendor/bin/greph -F -l "TODO" src

# Files that do not contain the pattern
./vendor/bin/greph -F -L "TODO" src

# Count matches per file
./vendor/bin/greph -F -c "TODO" src

# Inverted match
./vendor/bin/greph -F -v "TODO" src/notes.txt
```

## パターン

デフォルトでは、パターンはPCRE2正規表現として扱われます。PHPの`preg_*`関数がエンジンを支えるため、構文は[PHP PCREリファレンス](https://www.php.net/manual/en/pcre.pattern.php)]と一致します。

`-F`で正規表現エンジンを無効にすると、パターンはリテラルのバイト列として扱われます。固定文字列モードは高速な処理経路で、照合には`strpos()`を使い、PCRE2のコンパイル処理を完全に省略します。

`-i`を指定すると、どちらのモードも大文字と小文字を区別しません。`-w`を指定すると、マッチの両側に単語境界が追加されます。

## ファイルの絞り込み

Grephは検索前にファイルツリーを走査します。ウォーカーはASTモードおよびインデックスモードと共有されているため、同じフィルターフラグがすべてのモードに適用されます。

| フラグ | 効果 |
|---|---|
| `--type NAME` | 名前付きタイプエイリアス（`php`、`js`、`md`、...）に一致するファイルのみを含める |
| `--type-not NAME` | 名前付きタイプエイリアスに一致するファイルを除外する |
| `--glob GLOB` | パスがGLOBに一致するファイルのみを含める。複数回指定可能。 |
| `--no-ignore` | `.gitignore`または`.grephignore`を無視する |
| `--hidden` | 隠しファイルを含める |

ウォーカーはデフォルトで`.gitignore`と`.grephignore`を尊重し、バイナリファイル（先頭512バイト内のヌルバイトで検出）をスキップして、ファイルサイズを10 MiBまでに制限します。どちらの制限も`WalkOptions`で設定できます。

組み込みのタイプエイリアス一覧は[API / FileTypeFilter](https://greph.inline0.dev/ja/docs/api#grephwalkerfiletypefilter)]を参照してください。

## コンテキスト、件数、ファイルのみのモード

```bash
# Two lines before and after each match
./vendor/bin/greph -F -C 2 "needle" src

# Two lines after, no lines before
./vendor/bin/greph -F -A 2 "needle" src

# Two lines before, no lines after
./vendor/bin/greph -F -B 2 "needle" src

# Count matches per file
./vendor/bin/greph -F -c "needle" src

# List matching files only
./vendor/bin/greph -F -l "needle" src

# List non-matching files only
./vendor/bin/greph -F -L "needle" src
```

`-c`、`-l`、`-L`はフォーマッターを迂回するため、すべての行をメモリ上に展開せずに済みます。「いくつ」「どこに」という検索に適したモードです。

## 並列スキャン

`-j N`を渡すと、スキャンをN個のワーカーに振り分けます。Grephはワーカープールに`pcntl_fork()`を使用し、`ext-pcntl`が利用できない場合は単一プロセスで実行します。

```bash
./vendor/bin/greph -F -j 8 "function" src
```

ファサードは、ファイル数、モード、パターンの形状をもとに、並列実行のオーバーヘッドに見合うかどうかを判定します。しきい値を下回る場合は単一プロセスのまま実行します。判定方法については[Advanced / Parallel Workers](https://greph.inline0.dev/ja/docs/advanced/parallel)]を参照してください。

## JSON出力

`--json`は、grep形式の画面出力を解析せずに後続ツールが利用できる構造化ペイロードを出力します。

```bash
./vendor/bin/greph --json -F "function" src
```

```json
[
  {
    "file": "src/Greph.php",
    "matches": [
      {
        "line": 31,
        "column": 1,
        "content": "final class Greph",
        "matched_text": "function",
        "captures": []
      }
    ]
  }
]
```

`rg`ラッパーは、代わりにripgrepイベント形式のJSONを出力します。既存の利用側がripgrepスキーマを想定している場合に使用してください。

## プログラムからの利用

```php
use Greph\Greph;
use Greph\Text\TextSearchOptions;

$results = Greph::searchText(
    'function',
    'src',
    new TextSearchOptions(
        fixedString: true,
        caseInsensitive: true,
        beforeContext: 1,
        afterContext: 1,
        jobs: 4,
    ),
);

foreach ($results as $file) {
    foreach ($file->matches as $match) {
        echo "{$file->file}:{$match->line}:{$match->content}\n";
    }
}
```

結果オブジェクトについては[API / Result objects](https://greph.inline0.dev/ja/docs/api#result-objects)]を参照してください。

## 仕組み

テキストエンジンには2つの処理経路があります。

- **リテラル経路**：`-F`を設定すると、64 KiBのバッファ付きリーダーで`strpos()`を実行し、行番号を追跡するために改行を記録します。正規表現のコンパイル処理はありません。
- **正規表現経路**：`-F`を設定していない場合、Grephは小規模なPCRE形式の解析器（`Greph\Text\LiteralExtractor`）を使ってパターンからリテラル部分文字列を抽出し、`strpos()`の事前フィルターとして使用します。事前フィルターを通過した行は、JITを有効にしてコンパイルしたPCRE2パターンと照合されます。

どちらの経路も、I/Oには同じ`BufferedReader`を使用します。リーダーは`fgets()`単位ではなく64 KiB単位で読み込むため、大きなファイルではシステムコール数が大幅に減少します。

繰り返し実行するワークロードでは、[インデックス付きテキストモード](https://greph.inline0.dev/ja/docs/indexed/text)]がバッファ付きリーダーの代わりに、ウォームアップ済みのトライグラム＋識別子ポスティングストアを使うため、ほとんどのファイルを丸ごとスキップできます。
