跳转到正文

文本搜索

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

快速示例

命令行
# 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 参考一致。

使用 -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。

上下文、计数和仅文件模式

命令行
# 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 不可用时回退到单进程执行。

命令行
./vendor/bin/greph -F -j 8 "function" src

门面会根据文件数、模式和模式形态计算并行执行是否值得承担额外开销。低于阈值时会使用单进程执行。启发式规则请参阅 高级 / 并行工作进程。

JSON 输出

--json会输出结构化数据,供下游工具解析,无需从屏幕上抓取 grep 格式:

命令行
./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 / 结果对象。

工作原理

文本引擎有两条路径:

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

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

对于重复工作负载,索引文本模式会用预热后的三元组和标识符倒排索引存储替代缓冲读取器,并跳过大多数文件。