non-greedy PHP regexp

“non-greedy PHP regexp” – Du verstehst Bahnhof?
Ich versuche es allgemein verständlich zu erklären:

  • Eine immer wieder auftretende Programmier-Aufgabe ist es, aus einem Textblock bestimmte Text-Teile zu extrahieren. Dazu ist ein Muster nötig, nach der die Software den Text analysiert.
  • Beispieltext: “mein text: <b>fett</b> und nicht fett”
  • Die Aufgabe: Extrahiere den Text der zwischen “<b>” und “</b>”
  • Die Lösung ist der “reguläre Ausdruck” “<b>(.*)<\/b>”.
    Dabei steht “(.*)” für irgendeinen Text.
    Dieser reguläre Ausdruck wird z. B. in der PHP-Funktion preg_match verwendet:
    preg_match(“/regulärer Ausdruck/”, “zu durchsuchender Text”, $treffer)
    In der Variable $treffer steht dann das Suchergebnis. In unserem Beispiel ist das “fett”.
  • Soweit so gut.
    Was aber, wenn im Text das Suchmuster mehrmals vorhanden ist?
    Also der Text z. B. so ist: “mein text: <b>fett</b> und nicht fett. Hier aber noch <b>ein 2tes Mal fett</b> zum Ende”
  • Obiger preg_match mit dem regulären Ausdruck “<b>(.*)<\/b>” liefert den Text
    “fett</b> und nicht fett. Hier aber noch <b>ein 2tes Mal fett”.
    Denn das Suchmuster “<b>(.*)<\/b>” sucht den ersten “<b>” und den letzten “</b>”.
    “(.*)” steht für “irgendeinen Text”.
  • Damit beide Texte extrahiert werden ist folgendes nötig:
    Als Suchmuster “<b>(.*?)<\/b>” und preg_match_all
    Das “?” macht den regulären Ausdruck “non-greedy”, greedy steht für “gierig” im Sinne dass der längstmögliche Text extrahiert werden soll.
    non-greedy gibt die einzelnen Textstücke.
    preg_match_all extrahiert die komplette Liste der Suchtreffer – im Unterschied zu preg_match, das nur den ersten Treffer extrahiert.