Der beliebte PHP-Befehl preg_match_all() mit konkreten Beispielen genauer betrachtet.
Inhalt
Was macht preg_match_all()
Der PHP Befehl preg_match_all()
untersucht einen übergebenen String auf die Existenz eines festgelegten Suchpatterns (Regular Expression). Im Gegensatz zum bekannten preg_match()
liefert er alle Treffer zurück statt nur des ersten Treffers. So weit so gut, denn das kann man auch in PHP.net nachlesen. Doch zeichnet den Befehl etwas aus, was in der Dokumentation nicht so ganz deutlich wird, daher möchte ich diese Besonderheit noch einmal klarer mit einem konkreten Beispiel aus der Praxis hervorheben.
Parsing eines Textes nach numerischen Tokens
Als Demonstration, habe ich eine Aufgabenstellung aus einer CMS Programmierung, prototypisch als Codebeispiel ausgesucht. Der folgende Beispiel-Text ist angefüllt mit so genannten Tokens ala
{999}
Beispiel für einen numerischen Token
(Ziffern von 0-99999 die einen Bausteintext-ID aus einer Datenbank symbolisieren). Zur Laufzeit soll der Parser die Tokens durch die Textphrasen aus einer Datenbank ersetzen.
$data = <<<EOD
Dieser Beispieltext ist angefüllt mit so genannten Tokens, die das Programm mit einer {2468}
RegularExpression finden und {55} einsammeln soll. Alle Tokens in Form von {0} werden in
einem Array {3} zusammengetragen. Im Anschluss daran, soll das System diese Tokens {349}
durch Textbausteine aus einer Datenbank ersetzen.
EOD;
Dummy Text der mit Tokens gefüllt ist die ersetzt werden sollen
Auf den oben gezeigten Heredoc-Text wende ich unterschiedliche Patterns an und zeige wie diese wirken. Besonderes Augenmerk ist dabei auf die Setzung des runden Klammerpaars ()
zu achten, da die Position maßgeblich für das entstehende Ergebnis-Array $matches
ist.
'/{[0-9]*}/'
- der Klassiker
Beginnen wir mit dem Klassiker, den man sicherlich als erstes verwenden würde, wenn man mit dieser Aufgabenstellung beginnt:
preg_match_all('/{[0-9]*}/', $data, $matches)
Typischer RegEx zum finden von {399}
Dieser Befehl erzeugt ein recht erwartbares Array wie folgt:
array(1)
{
[0]=> array(8)
{
[0]=> string(6) "{2468}"
[1]=> string(4) "{55}"
[2]=> string(3) "{0}"
[3]=> string(3) "{3}"
[4]=> string(5) "{349}"
}
}
RegEx: Ergebnis Array
Die Delimiter /
leiten das Pattern ein und beenden es mit /
. Die RegEx findet folglich alles Stellen die numerisch {0}
bis {99999...}
reichen.
Tipp: Das Pattern
[0-9]
würde lediglich einstellige Muster finden, während[0-9]*
auch mehrstellige numerische Suchmuster ermitteln kann und genau das soll ja Ziel sein.
'/({)[0-9]*(})/'
- schon besser
Setzen Sie nun die geschweiften Klammern { je zwischen zwei runde Klammern, also so:
({)...(})
RegEx mit runden Klammern
erzeugt der Befehl:
preg_match_all('/({)[0-9]*(})/', $data, $matches)
RegEx Version 2
eine ganz andere Array-Struktur. Der Befehl erzeugt für jedes Paar ()
ein eigenes Array und ein Array mit dem Ergebnis das sich zwischen den beiden Klammerpaaren ermittelt:
array(3)
{
[0]=> array(8)
{
[0]=> string(6) "{2468}"
[1]=> string(4) "{55}"
[2]=> string(3) "{0}"
[3]=> string(3) "{3}"
[4]=> string(5) "{349}"
}
[1]=> array(8)
{
[0]=> string(1) "{"
[1]=> string(1) "{"
[2]=> string(1) "{"
[3]=> string(1) "{"
[4]=> string(1) "{"
}
[2]=> array(8)
{
[0]=> string(1) "}"
[1]=> string(1) "}"
[2]=> string(1) "}"
[3]=> string(1) "}"
[4]=> string(1) "}"
}
}
Ergebnis-Array der RegEx
'/{([0-9]*)}/'
die beste Wahl
Das gewünschte Ergebnis stellt sich für die oben gezeigte Aufgabenstellung jedoch mit diesem Pattern ein:
/{([0-9]*)}/
RegEx: numerisch extrahieren
dabei ist der numerische Anteil des Pattern geklammert und erzeugt damit ein dazu passendes Ergebnis-Array in $matches
. Der folgende Befehl:
preg_match_all('/{([0-9]*)}/', $data, $matches)
RegEx: extrahieren des numerischen Anteil
führt daher zu dem volgenden Ergebnis:
array(2)
{
[0]=> array(8)
{
[0]=> string(6) "{2468}"
[1]=> string(4) "{55}"
[2]=> string(3) "{0}"
[3]=> string(3) "{3}"
[4]=> string(5) "{349}"
}
[1]=> array(8)
{
[0]=> string(4) "2468"
[1]=> string(2) "55"
[2]=> string(1) "0"
[3]=> string(1) "3"
[4]=> string(3) "349"
}
}
Der numerische Teil ist geklammert und wird als eigenes Array erzeugt
Sofern also der numerische Wert im Token {399}
die Textbaustein-ID eines Eintrages in einer Datenbank wiederspiegeln soll, kann mit dem Array $matches[1]
darüber iteriert werden und daraus ein SELECT
erzeugt werden, etwa so:
foreach($matches as $value)
{
$sql = 'SELECT * FROM docbin_baustein WHERE id = '.$value;
$result = ...
}
Verwendung der Trefferliste als ID-Geber für SELECT
Beispiel: öffnende und schließende HTML-Tags
Für die folgenden RegEx-Beispiele, soll der folgende Demotext als Quelle dienen:
<h1>Lorem Ipsum</h1>
<p class="fw-bold">Das ist der Inhalt des Beitrags für das RegEx Pattern.</p>
<h2>Dolor sit amet</h2>
<p class="fw-bold">Das ist der Inhalt des Beitrags für das RegEx Pattern.</p>
Demo-Text
Zunächst ein interessantes Pattern aus der PHP-Dokumentation:
preg_match_all("|<[^>]+>(.*)</[^>]+>|U", $data, $matches);
RegEx Pattern aus der Doku
Das oben gezeigte Pattern extrahiert alle <.> - </.>
Tags aus dem Content und zerlegt die Treffer in zwei Arrays:
array(2)
{
[0]=> array(4)
{
[0]=> string(20) "<h1>Lorem Ipsum</h1>"
[1]=> string(78) "<p class="fw-bold">Das ist der Inhalt des Beitrags für das RegEx Pattern.</p>"
[2]=> string(23) "<h2>Dolor sit amet</h2>"
[3]=> string(78) "<p class="fw-bold">Das ist der Inhalt des Beitrags für das RegEx Pattern.</p>"
}
[1]=> array(4)
{
[0]=> string(11) "Lorem Ipsum"
[1]=> string(55) "Das ist der Inhalt des Beitrags für das RegEx Pattern."
[2]=> string(14) "Dolor sit amet"
[3]=> string(55) "Das ist der Inhalt des Beitrags für das RegEx Pattern."
}
}
Ergebnis-Array der RegEx
Im Array $matches[1]
kann über die reinen ASCII-Inhalte iteriert werden, während das Array $matches[0]
zusätzlich die HTML-Tokens enthält. Je nach Geschmack kann eines der beiden Arrays genutzt werden.
Beispiel: H-Tags extrahieren
Im zweiten Beispiel, sollen die H-Tags extrahiert werden, dazu reicht es aus, das eingans gezeigte Pattern um h
zu erweitern, also so:
preg_match_all("|<h[^>]+>(.*)</h[^>]+>|U", $data, $matches);
RegEx: H-tags extrahieren
um das folgende Ergebnis zu erhalten:
array(2)
{
[0]=> array(2)
{
[0]=> string(20) "<h1>Lorem Ipsum</h1>"
[1]=> string(23) "<h2>Dolor sit amet</h2>"
}
[1]=> array(2)
{
[0]=> string(11) "Lorem Ipsum"
[1]=> string(14) "Dolor sit amet"
}
}
Ergebnis-Array der RegEx
Beispiel: P-Tags und class extrahieren
Im dritten Beispiel können Sie mit dem folgenden Pattern alle P-Tags und den Inhalt zwischen Start und Ende der Tags extrahieren:
preg_match_all('/<[p].*>(.*)<\/[p]>/', $data, $matches);
RegEx: P-Tags extrahieren
Mit diesem RegEx-Pattern erhalten Sie das folgende Array:
array(2)
{
[0]=> array(2)
{
[0]=> string(78) "<p class="fw-bold">Das ist der Inhalt des Beitrags für das RegEx Pattern.</p>"
[1]=> string(62) "<p>Das ist der Inhalt des Beitrags für das RegEx Pattern.</p>"
}
[1]=> array(2)
{
[0]=> string(55) "Das ist der Inhalt des Beitrags für das RegEx Pattern."
[1]=> string(55) "Das ist der Inhalt des Beitrags für das RegEx Pattern."
}
}
Ergebnis-Array der RegEx
Sie extrahieren alle Inhalte zwischen den P-Tags in $matches[1]
bzw. die vollständigen Treffermuster mit HTML-Tags in $matches[0]
. Möchten Sie zudem auch noch die class="..." Spezifizierung ermitteln, dann müssen Sie ein Klammerpar in /<[p].*
einfügen, folglich /<[p](.*)
. Mit dem Befehl:
preg_match_all('/<[p](.*)>(.*)<\/[p]>/', $data, $matches);
RegEx: zum extrahieren der P-Tags und Class-Attribute
entsteht das folgende Array:
array(3)
{
[0]=> array(2)
{
[0]=> string(78) "<p class="fw-bold">Das ist der Inhalt des Beitrags für das RegEx Pattern.</p>"
[1]=> string(62) "<p>Das ist der Inhalt des Beitrags für das RegEx Pattern.</p>"
}
[1]=> array(2)
{
[0]=> string(16) " class="fw-bold""
[1]=> string(0) ""
}
[2]=> array(2)
{
[0]=> string(55) "Das ist der Inhalt des Beitrags für das RegEx Pattern."
[1]=> string(55) "Das ist der Inhalt des Beitrags für das RegEx Pattern."
}
}
Ergebnis-Array der RegEx
Folglich enthält $matches[1]
alle Treffer zu den Parametern hinter dem P im öffnenden P-Tag, meist sind das Class-Parameter oder ID-Angaben.
28.01.2024 Kontakt@Oliver-Lohse.de preg_match RegEx Regular Expression