Zum Inhalt springen

Textsuche

Der Textmodus von Greph durchsucht einen durchsuchten Dateibaum zeilenweise nach Bytes. Er ist der Standardmodus der greph-CLI und der Greph::searchText()-Fassade. Die Ausgabe verwendet das kanonische Format file:line:content, das grep, ripgrep und die meisten Editorintegrationen verarbeiten können.

Schnellbeispiele

Shell
# 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

Muster

Standardmäßig wird das Muster als regulärer PCRE2-Ausdruck behandelt. Die Funktionen preg_* von PHP bilden die Grundlage der Engine, daher entspricht die Syntax der PHP PCRE-Referenz.

Deaktiviere die Regex-Engine mit -F, um das Muster als literale Bytefolge zu behandeln. Der Modus für feste Zeichenfolgen ist der schnelle Pfad: Er verwendet strpos() für den Abgleich und überspringt den PCRE2-Kompilierschritt vollständig.

-i macht beide Modi unabhängig von Groß- und Kleinschreibung. -w fügt auf beiden Seiten des Treffers Wortgrenzen hinzu.

Dateien filtern

Greph durchläuft den Dateibaum vor der Suche. Der Datei-Scanner wird mit dem AST-Modus und dem Indexmodus geteilt, daher gelten dieselben Filteroptionen überall.

Option Wirkung
--type NAME Nur Dateien einschließen, die dem benannten Typalias entsprechen (php, js, md, ...)
--type-not NAME Dateien ausschließen, die dem benannten Typalias entsprechen
--glob GLOB Nur Dateien einschließen, deren Pfade auf GLOB passen. Wiederholbar.
--no-ignore .gitignore oder .grephignore nicht beachten
--hidden Versteckte Dateien einschließen

Der Datei-Scanner beachtet standardmäßig .gitignore und .grephignore, überspringt Binärdateien (erkannt anhand von Nullbytes in den ersten 512 Bytes) und begrenzt die Dateigröße auf 10 MiB. Beide Grenzwerte lassen sich über WalkOptions konfigurieren.

Eine vollständige Liste der integrierten Typaliasse findest du unter API / FileTypeFilter.

Kontext, Trefferzahlen und reine Dateimodi

Shell
# 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 und -L umgehen den Formatierer direkt und vermeiden so, jede Zeile im Speicher abzulegen. Sie eignen sich für Abfragen wie „wie viele“ und „wo“.

Parallele Scans

Übergib -j N, um den Scan auf N Worker zu verteilen. Greph verwendet pcntl_fork() für den Worker-Pool und greift auf die Ausführung in einem einzelnen Prozess zurück, wenn ext-pcntl nicht verfügbar ist.

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

Die Fassade berechnet anhand der Dateianzahl, des Modus und der Musterform, ob sich parallele Ausführung lohnt. Unterhalb des Schwellenwerts bleibt sie bei einem einzelnen Prozess. Die Heuristiken findest du unter Advanced / Parallel Workers.

JSON-Ausgabe

--json gibt eine strukturierte Nutzlast aus, die nachgelagerte Werkzeuge ohne Auslesen des Bildschirmausgabeformats von grep verarbeiten können:

Shell
./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": []
      }
    ]
  }
]

Der Wrapper rg gibt stattdessen Ereignisse im Format von ripgrep als JSON aus. Verwende ihn, wenn ein vorhandener Verbraucher das ripgrep-Schema erwartet.

Programmatische Verwendung

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";
    }
}

Die Ergebnisobjekte sind unter API / Result objects dokumentiert.

So funktioniert es

Die Text-Engine hat zwei Pfade:

  • Literaler Pfad: Wenn -F gesetzt ist, durchsucht strpos() einen 64-KiB-gepufferten Reader und erfasst Zeilenumbrüche zur Zeilennummerierung. Es gibt keinen Schritt zum Kompilieren eines regulären Ausdrucks.
  • Regex-Pfad: Wenn -F nicht gesetzt ist, extrahiert Greph mit einem kleinen PCRE-ähnlichen Analysator (Greph\Text\LiteralExtractor) literale Teilzeichenfolgen aus dem Muster und verwendet sie als strpos()-Vorfilter. Zeilen, die den Vorfilter passieren, werden anschließend mit dem kompilierten PCRE2-Muster und aktiviertem JIT abgeglichen.

Beide Pfade verwenden dasselbe BufferedReader für die Ein-/Ausgabe. Der Reader liest Daten in 64-KiB-Blöcken statt fgets() pro Zeile, wodurch die Anzahl der Systemaufrufe bei großen Dateien deutlich sinkt.

Bei wiederholten Arbeitslasten ersetzt der indexierte Textmodus den gepufferten Reader durch einen aufgewärmten Trigramm- und Bezeichner-Posting-Speicher und überspringt die meisten Dateien vollständig.