(Hallo|Hi(ho)|Tag) Dieter,
Ich möchte einen Stringbereich zwischen zwei Begrenzungswerten (in diesem Fall doppelte eckige Klammern) austauschen, sowie den ursprünglichen Inhalt in einem Array speichern.
Das sieht auf den ersten Blick wie Links in MediaWiki-Quellcodes aus. Also
könnte es sich lohnen mal im MediaWiki-Quellcode nachzuschauen. Irgendwo
dort sollte sowohl der passende RegEx, als auch die dazugehörige
Ersetzungsstrategie zu finden sein. ;-)
Naja, ich mal schnell was zusammengestrickt, was zumindest mit
deinem Testsatz zurechtkommt:
$haystack = 'Das ist ein Testsatz. Dieser Testsatz ist in einem [[String]]
gespeichert und soll via preg_replace [[Arbeit|bearbeitet]] werden -- leider
sind aber meine bisherigen [[Bemühung|Bemühungen]] recht erfolglos.';
$pfad = 'PFAD/';
$pcre = '/\[\[([^\x7c\]]+)(\x7c(.+))?\]\]/e';
$rpl = 'sprintf(
\'{a href="' . $pfad . '%s"}%s{/a}\',
"$1",
( "$3" ? "$3" : "$1" )
)';
$out = preg_replace($pcre, $rpl, $haystack);
a) wo ist mein Fehler bzw. was muß ich an der regexp verändern (bitte wenn möglich auch mit Erklährung, damit ich auch verstehe was falsch gelaufen ist)
Das Suchmuster $pcre besteht aus den umgebenden doppelten eckigen Klammern.
Darin befinden sich zwei Subpattern in runden Klammern. Das erste
"([^\x7c]]+)" passt auf mindestens ein oder eine beliebige Zahl von
Zeichen, die nicht der vertikale Trennstrich "\x7c" und auch nicht eine
schließende eckige Klammer "]" darstellen.
Das zweite "(\x7c(.+))?" passt auf die Zeichenfolge "|" plus ein oder
mehrere beliebige Zeichen. Das Muster "(.+)" ist als drittes
Subpattern nötig, weil wir ja beim Ersetzen nur den Text nach dem
senkrechten Strich brauchen.
Der Modifikator "/e" sorgt dafür, dass der Ersetzen-String $rpl als
PHP-Code ausgeführt wird. Das ist nötig, da wir ja eine Fallunterscheidung
treffen müssen: Ist das Subpattern Nummer 3 gefunden worden, wird
es im Ausgabe-String eingesetzt, wenn nicht, übernimmt Subpattern 1
diese Aufgabe.
Man könnte den Ersetzen-String auch anders basteln. Ich habe für die
Fallunterscheidung den Konditionaloperator
("is_wahr ? dann_nimm_meinen_wert : nö,_dann_nimm_meinen_wert")
und sprintf() missbraucht. Glücklicherweise wertet PHP leere Zeichenketten als
"nicht TRUE", deshalb gibt
( "$3" ? "$3" : "$1" )
den Wert von "$1" zurück, wenn das Subpattern 3 nicht gepasst hat.
Das Ganze ist eher als Prototyp zu verstehen. Vor allem solltest du das
Verhalten beim Auftreten der Zeichen "|", "[", "]" und eventuell noch
anderer für dein Script bedeutsamer Steuerzeichen testen, damit nicht
"kaputte Pfadangaben" nach der Ersetzung herauskommen. Im Moment frisst
das Suchmuster auch Zeichenketten, die über mehrere Zeilen gehen. Am
besten machst du dir erstmal klar, welche Zeichen im Pfadbestandteil
überhaupt erlaubt sind. Eventuell müssen sie auch noch URL-enkodiert
werden.
Auch kann man mit preg_replace_callback und einer anonymen Funktion
übersichtlicheren Quellcode und ein schnelleres Script produzieren.
b) wie kann ich zudem den Wert "\1" in ein Array bekommen ?
Das ist schwierig. Mit preg_replace_callback() kommst du zwar an den
Wert, aber du kannst ihn nur über eine globale Hilfs-Variable an das Script
weitergeben. Sauberer wäre aus meiner Sicht eine Lösung mit preg-match(),
dessen Offset-Parameter und PREG_OFFSET_CAPTURE in einer Schleife.
... oder du teilst mit [preg_split() den Text in ein Array aus gewöhnlichen
Textstücken und Links, ersetzt dann alle Links durch den passenden
HTML-Quelltext und schraubst das Array am Schluss wieder zu einer
Zeichenkette zusammen.
MffG
EisFuX