non-greedy PHP regexp

non-greedy PHP regex

„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.