back references bei verschachtelten preg_replace (e-modifier)
molily
- php
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...?)
Hi molily,
$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
wenn ich das Problem richtig verstanden habe, könnte es so gehen:
$string = preg_replace('/murks/e','"p".substr($0,1)','textmurkstext');
Vermutlich wird substr() gegenüber einem weiteren regulären Ausdruck auch die Performance fördern...
HTH Robert
[Wohl wissend, daß Einmischungen in die Angelegenheiten des Inner Circles nicht gerne gesehen werden...]
Hallo srob,
[Wohl wissend, daß Einmischungen in die Angelegenheiten des
Inner Circles nicht gerne gesehen werden...]
Welcher Inner Circle? Welche Einmischung?
Man, man, man.
Gruesse,
CK
Welcher Inner Circle? Welche Einmischung?
Hallo Christian,
sorry - wahrscheinlich habe ich montag morgens noch zu viel gute Laune, um mir so etwas verkneifen zu können.
Vielleicht kennst Du aus der Zeit, als Du noch jung warst, diese beispielhafte Situation: Auf dem Schulhof steht eine Clique - das ist der Inner Circle - zusammen und unterhält sich angeregt über ein Thema. Ein Nichtmitglied dieser sozialen Gruppierung, das zufällig anwesend ist, schaltet sich mit einer Bemerkung in die Unterhaltung ein - das ist die Einmischung. Schlagartig drehen sich die Köpfe in Richtung des Sprechers, für eine Sekunde verstummen alle, Adrenalinspiegel schnellen mit den üblichen Folgen in die Höhe (Herz- und Atemfrequenz steigen, Pupillen verengen sich, Muskelspannungen erhöhen sich), dann drehen sich die Köpfe wieder zurück und das Gespräch fließt angeregt weiter als wäre nie ein Einwurf von außen gekommen, mag er noch so kompetent und angemessen gewesen sein. Ein ganz alltäglicher gruppendynamischer Vorgang.
Ob der Vorgang so oder anders abläuft, hängt von etwas ab, für das ich keinen offiziellen Begriff kenne - ich würde es als den "sozialen Ethos" der Gruppe bezeichnen. In dieser sozialen Gruppe hier (SELFHTML Forum) beobachte ich häufig eine Reaktion der Stamm-Mitglieder, die der oben beschriebenen gleicht (oder auch oft: ein Abbau der angesammelten Spannung durch ein In-Fetzen-Reißen des Außenstehenden). Ich kenne andere Entwicklerforen, in denen mir noch nie - selbst bei aggressiven Verhaltensweisen von nicht Initiierten - solche Reaktionen begegneten. Keine Ahnung, warum das hier so ist, vielleicht hängt es auch mit dem Alterdurchschnitt zusammen.
Wahrscheinlich stehen mir Äußerungen dieser Art jedoch nicht zu; ich meine mich zu erinnern, daß ich schon einmal eine ähnliche Diskussion hier hatte ("Die üblichen Verdächtigen"). Ich werde versuchen, nicht mehr zu polemisieren - wie gesagt, Montag morgen...
Tut mir leid!
Gruß
Robert
Hallo srob,
sorry
Wofuer?
Vielleicht kennst Du aus der Zeit, als Du noch jung warst,
diese beispielhafte Situation: [...]
Nur zu gut.
In dieser sozialen Gruppe hier (SELFHTML Forum) beobachte
ich häufig eine Reaktion der Stamm-Mitglieder, die der
oben beschriebenen gleicht (oder auch oft: ein Abbau der
angesammelten Spannung durch ein In-Fetzen-Reißen des
Außenstehenden).
Das habe ich bisher nur bei provokanten Postings so
erlebt/beobachtet. Hier wird keiner angemacht, wenn er eine
kompetente Antwort postet -- hoffe ich zumindest. Wenn doch,
dann mache bitte darauf aufmerksam, das kann nicht richtig
sein.
Wahrscheinlich stehen mir Äußerungen dieser Art jedoch
nicht zu; ich meine mich zu erinnern, daß ich schon einmal
eine ähnliche Diskussion hier hatte ("Die üblichen
Verdächtigen").
An den Thread kann ich mich erinnern. Und die von dir dort
genannten Argumente wurden IMHO alle widerlegt.
Ich werde versuchen, nicht mehr zu polemisieren
Das waere schonmal ein Anfang ;)
Gruesse,
CK
Hallo, Robert,
$string=preg_replace('~murks~e', 'preg_replace("~m(urks)~", "p\\1", "\0")', 'textmurkstext');
wenn ich das Problem richtig verstanden habe, könnte es so gehen:
$string = preg_replace('/murks/e','"p".substr($0,1)','textmurkstext');
Klar, das löst das Problem des Beispiels, aber das war eben nur ein vereinfachendes Beispiel um das Problem der back references zu verdeutlichen, mir ist natürlich bekannt dass sich *diese* spezielle Aufgabe viel einfacher lösen lässt...
Heureka, Du hast mir den entscheidenden Tipp gegeben, nämlich $[\d] als back reference zu nutzen, beziehungsweise $[\d]... mir war nicht bekannt, dass das möglich ist, es funktioniert wunderprächtig[tm]. Damit dürfte meine atemberaubende Konstruktion das gewünschte Ergebnis bringen.
[Wohl wissend, daß Einmischungen in die Angelegenheiten des Inner Circles nicht gerne gesehen werden...]
Mit dem Feature-Artikel, den ich schreibe, darf ich immer noch machen was ich will... *fg* Im Übrigen hat Christian Seiler danach gefragt, ob ich ihm mein Set an RegExps zur Verfügung stellen kann, da wollte ich sie noch einmal überarbeiten, sodass sie mit geringen Änderungen auf nahezu jede Seite im Self-Layout passen... ganz... konspirativ, sozusagen. ;))
Grüße,
Mathias
Hallo Mathias,
Im Übrigen hat Christian Seiler danach gefragt, ob ich ihm mein Set an RegExps zur Verfügung stellen kann, da wollte ich sie noch einmal überarbeiten, sodass sie mit geringen Änderungen auf nahezu jede Seite im Self-Layout passen... ganz... konspirativ, sozusagen. ;))
Erwischt! Jetzt weiß ich endlich, wo Du Deine regulären Ausdrücke herhast. Tztztz ;-)
Trotzdem Danke, ich werd' sie mir mal anschauen. (inzwischen hab' ich die PHP-Datei schon runtergeladen)
Grüße,
Christian
Hallo, Christian,
Im Übrigen hat Christian Seiler danach gefragt, ob ich ihm mein Set an RegExps zur Verfügung stellen kann, da wollte ich sie noch einmal überarbeiten, sodass sie mit geringen Änderungen auf nahezu jede Seite im Self-Layout passen... ganz... konspirativ, sozusagen. ;))
Erwischt! Jetzt weiß ich endlich, wo Du Deine regulären Ausdrücke herhast. Tztztz ;-)
Na klar, ich bin derjenige der hier täglich die dummen Fragen bezüglich RegExps stellt, mal unter (PERL), mal unter (PHP) und zur Verwirrung unter (ASP), immer unter anderem Namen; ich bin ein Meister der Verwandlung, Imitationslernen nennt sich so etwas. ;) Ich bin auch immer derjenige, der dann unter dem Namen 'molily' patzige Antworten gibt und arrogant auf das Archiv verweist... ;) So lebt man eben seine Schizophrenie aus... Meinen "Zöglingen" werde ich wohlwissentlich "Mastering Regular Expressions" schon in frühester Kindeheit einbläuen... ("damit sie es später einmal besser haben") ;)
Den "Dislaimer" habe ich übrigens schon im ersten Satz meines Ursprungspostings untergebracht... [pref:t=29786&m=161151]. ;)
Andreas Korthaus hatte hier einmal eine Archivsuche vorgestellt, welche jeweils nur die gestarteten Threads auflistete, ich war eben überrascht, dass ich bei hunderten Postings nur zwei oder drei Threads gestartet habe... "Ich habe auch ein Recht auf Fragen", *g* beschämend war die Tatsache, dass Robert das "Problem" im Vorbeigehen gelöst hat... Mal wieder ein typisches "es war mir entfallen"-Problem, siehe auch http://cforum.teamone.de/forum/my/?t=28233&m=152990...
Trotzdem Danke, ich werd' sie mir mal anschauen. (inzwischen hab' ich die PHP-Datei schon runtergeladen)
Das ist ein Anfang. ;) Ich lasse dich wissen, falls^Wwenn ich mich an die Programmierung des allgemeinen Wandler begebe; da ich noch einige andere Artikel vermutlich im Self-Raum veröffentlichen möchte (als Reputationsschmarotzer[tm], der ich nun einmal bin ;)), wird das wohl sehr bald sein (vielleicht sogar noch in diesem Jahr *g*).
Mathias