molily: back references bei verschachtelten preg_replace (e-modifier)

Beitrag lesen

Hallo zusammen,

Sieh an, ich starte einen Thread, das ist etwas ganz Seltenes. Für gewöhnlich finde ich selbst eine Lösung für meine Probleme (zumindest [...], wie auch immer, lol) ohne das Kollektiv zu bemühen, aber diesmal stehe ich vor einem Rätsel, was mich in der Regel dazu verleitet, einen anderen Weg zu wählen (TIMTOWTDI, nicht nur bei Perl), nur in diesem Fall wäre eine anderer Weg extrem ineffektiv, denn er würde direkt ganze circa fünf und indirekt ganze fünfzehn Zeilen mehr Code mehr bedeuten - absolut un-31337! ;)) Es ist folglich nicht wirklich ein Problem, lediglich ein stures Beharren auf den komplizierten aber (enorm ;)) codesparenden Weg. (Ich wäre sicherlich schon längst fertig, wenn ich das Problem umschifft hätte... *fg*)

Es geht im Groben darum, das ich ein Script schreiben möchte, welches Seiten im momentanen Self-Layout in ein XHTML-Layout umwandelt, das heißt vor allem die Layouttabellen zu zerhacken. Dazu möchte ich speziell das Inhaltsverzeichnis mit Regulären Ausdrücken extrahieren und in eine ungeordnete Liste überführen. Das alleine lässt sich mit zwei preg_replace-Anweisungen ist die Arbeit getan, der Haken: ich habe mir selbst das Ziel gesetzt, es in *einer* preg_replace-Anweisung zu schaffen, damit ich den Algorithmus, in einen Array mit allen weiteren nötigen Suchen/Ersetzen-Anweisungen einreihen kann.

Ich dachte an den pattern modifier "e" und daran, die zweite preg_replace-Anweisung im zweiten Parameter unterzubringen (preg_replace_callback ist auch nicht erlaubt, habe ich mir vorgegeben *fg*). Das Problem ist, dass ich nicht weiß, wie ich in der inneren preg_replace auf die Ergebnisse selbiger mit back references verweise.

Vereinfacht sieht das Problem folgendermaßen aus:

$string=preg_replace('~murks~e', 'preg_replace("~m(urks)~", "p\\1", "\0")', 'textmurkstext');

Zuerst wird der Text murks aus dem String textmurkstext extrahiert, um an ihm eine weitere Ersetzung vorzunehmen: der erste Buchstabe wird durch p ausgetauscht. Der Inhalt von $string sollte sein:

textpurkstext

Er ist jedoch:

textptext

...weil die back reference \\1 wahrscheinlich als SOH, also ASCII 001 angesehen wird. Mit \1 geht es übrigens auch nicht, was naheliegend wäre, aber \0 ist äquivalent zu \0 und beinhaltet das Ergebnis des äußeren preg_replace.

Ungeschnitten sieht die komplette Anweisung folgendermaßen aus, ich habe die Newslines zur Übersicht eingefügt, sie sind nicht nötig:

$string=preg_replace(
 '~<td bgcolor="#ffffff" valign="top" nowrap="nowrap">\s*<p>\s*(<a href="#([^"]+)"><b>(.+)</b></a>(<br />))+\s*</p>\s*</td>~siUe',
 '
  "<ul>\n".
  preg_replace(
   "~<a href="#([^"]+)"><b>(.+)</b></a><br />~siU",
   "<li><a href="#\\1">\\2</a></li>", "\1"
  ).
  "\n</ul>"
 ',
 $string
);

Die Ausgabe ist wiederum (logischerweise):

<ul>
<li><a href="#"></a></li>
...
</ul>

Ich habe nicht sonderlich Hoffnung, dass es eine elegante Lösung für die spezielle Aufgabenstellung gibt (das darüberliegende Problem lässt sich wie gesagt auch anders lösen), auch das Begrenzen des Strings mit der inneren preg_replace-Anweisung mit double quotes und entsprechendes Verwenden von single quotes darin oder maskierten double quotes bringt keine Verbesserung, im Gegenteil, es gibt einen seltsamen Parserfehler bezüglich des inneren Codes...

Vielleicht hat jemand eine zündende Idee... Mit Sicherheit sehe ich den Wald vor lauter Bäumen nicht und übersehe eine Möglichkeit, wie man mir insgesamt einem preg_replace auskommt...
Ehrlich gesagt hätte ich mir gewünscht, dass die erste RegExp eine andere Trefferliste auswirft, bei einem String wie in [0] und der oben beschriebenen äußeren RegExp ist der matches-Array bei preg_match:

Array
(
    [0] => <td bgcolor="#ffffff" valign="top" nowrap="nowrap">
<p>
<a href="#a1"><b>murks</b></a><br />
<a href="#a2"><b>purks</b></a><br />
</p>
</td>
    [1] => <a href="#a1"><b>murks</b></a><br />
<a href="#a2"><b>purks</b></a><br />
    [2] => a1
    [3] => murks</b></a><br />
<a href="#a2"><b>purks
    [4] => <br />
)

Ich hätte erwartet beziehungsweise hätte mir gewünscht ;), dass a1 und a2 und murks und purks einzeln auftauchen (in einem Unterarray beispielsweise, und nein, preg_match_all hilft auch nicht) - das was in [3] passiert ist mir schleierhaft, denn U für ungreedy ist gesetzt, auch ein explizites ? hinter jedem subpattern nützt nichts... HUALP! :)

Grüße,
Mathias
(Habe ich ausreichend Verwirrung gestiftet...?)

--
"Die größten Kritiker der Elche waren früher selber welche"
(Prof. Fritz Weigle alias F. W. Bernstein)