
# 文本搜索

Greph的文本模式会遍历文件树，并按行执行字节搜索。它是 `greph` CLI 和 `Greph::searchText()`门面的默认模式。输出采用标准 `file:line:content` 格式，grep、ripgrep和大多数编辑器集成都能解析。

## 快速示例

```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_*` 函数提供支持，因此语法与 [PHPPCRE 参考](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/zh/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
```

门面会根据文件数、模式和模式形态计算并行执行是否值得承担额外开销。低于阈值时会使用单进程执行。启发式规则请参阅 [高级 / 并行工作进程](https://greph.inline0.dev/zh/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 / 结果对象](https://greph.inline0.dev/zh/docs/api#result-objects)。

## 工作原理

文本引擎有两条路径：

- **字面路径**：设置 `-F` 时，搜索会通过 64 KiB 缓冲读取器运行 `strpos()`，并跟踪换行符以确定行号。不会编译正则表达式。
- **正则路径**：未设置 `-F` 时，Greph会使用小型 PCRE 形态分析器（`Greph\Text\LiteralExtractor`）从模式中提取字面子串，并将其用作 `strpos()` 预筛选器。通过预筛选的行随后会使用启用了 JIT 的已编译 PCRE2 模式进行匹配。

两条路径都使用相同的 `BufferedReader` 进行 I/O。读取器每次读取 64 KiB 数据，而不是每行读取一次 `fgets()`，这能大幅减少大型文件中的系统调用次数。

对于重复工作负载，[索引文本模式](https://greph.inline0.dev/zh/docs/indexed/text)会用预热后的三元组和标识符倒排索引存储替代缓冲读取器，并跳过大多数文件。
