preg_replace_callback-> Funktionsweise
romy
- php
Hi,
ich versuche eine Lin keersetzung mittels preg_replace_callback zu kreieren, leider scheitert es an einem kleinem Problem...
Wenn ich einfach nur die Funktion aufrufe und im gleichen Text eine andere (nämlich die callback-Funktion) definiert habe, funktioniert es tadellos.
Bsp. (von php.net)
<?php
$text = "April fools day is 04/01/2002\n";
$text.= "Last christmas was 12/24/2001\n";
// the callback function
function next_year($matches) {
// as usual: $matches[0] is the complete match
// $matches[1] the match for the first subpattern
// enclosed in '(...)' and so on
return $matches[1].($matches[2]+1);
}
echo preg_replace_callback(
"|(\d{2}/\d{2}/)(\d{4})|",
"next_year",
$text);
?>
wenn ich jetzt aber den gesamten COde in einer FUnktion kapseln will, weiss ich nicht mehr wo die Callback-Funktion hinkommt. Innerhalb der Funktion wieder eine Funktion deklarieren finde ich komisch und einfach ausserhalb geht nicht. Ich weiss leider nicht was für ein FEhler auftritt, es erscheint nur die Ausgabe nicht richtig (bzw. gar nicht, wie in diesem Beispiel)
Beispiel:
<?php
function hallo() {
$text = "April fools day is 04/01/2002\n";
$text.= "Last christmas was 12/24/2001\n";
echo preg_replace_callback(
"|(\d{2}/\d{2}/)(\d{4})|",
"next_year",
$text);
}
// the callback function
function next_year($matches) {
return $matches[1].($matches[2]+1);
}
?>
Was kann ich da tun?
ciao
romy
Hi,
okay es lag wohl an mir, dieses einfache Beispiel funktioniert
ABER:
Wenn ich jetzt die callback-funktion nicht $matches zurückgeben lasse, sondern nur 1 oder so, funktioniert auch dies bei diesem Beispiel okay. Versuche ich es auf meine Problematik zu münzen kommt nur Unsinn raus...
beispiel
<?php
function setLink($file) {
if(file_exists($file)){
# file_string includes the whole site-string
$file_string = implode("",(@file($file)));
// in $file_string steht das drin was auch drinstehen soll, einfach eine //html-seite mit ein paar links und ein bisschen Schrift
# finds a - tags
$pattern = '=^(.*)<a(.*)href="?(\S+)"([^>]*)>(.*)</a>(.*)$=msi';
return preg_replace_callback($pattern, "callback_setLink", $file_string);
}else {
return 0;
}
}
function callback_setlink($matches){
return 1;
}
?>
<html>
<head>
<title> test </title>
</head>
<body>
<textarea style="width:400px; height:300px">
<?
echo setLink("test.html");
?>
<!-- test.html
blabaohdsf
asdöfj
sdfo
<a href="test.htm">is</a>
<a href="test.htm">is</a>
<a href="test.htm">is</a>
djoi
-->
</textarea>
</body>
</html>
Ich würde nun vermuten das mir auch meine Seite mit der Schrift und anstatt der links nun eine 1 ausgegeben wird, aber nein es steht nur eine 1 da. Wohin ist der Text?
danke
ciao
romy
Hi,
naja, so komme ich nicht weiter...
das eigentliche Problem besteht immernoch wie eh und je.
Eigentlich wollte ich ja erreichen, dass alle matches gefunden und ersetzt werden, aber selbst preg_replace_callback, ersetzt jeweils nur das Erstgefundene. Wenn ich nicht in eine endlos-Schleife rutschen will muss ich mir also was anderes überlegen...aber was. Habe keine Funktion finden können, die das erfüllt was ich möchte und finde leider auch keinen Ansatz zum selber schreiben.
Hat bitte jemand eine Idee?
ciao
romy
Hi,
des Rätsels Lösung könnten "Modifier" sein. Das sind Schalter/Parameter für die Verhaltensweise der Suche.
Bye
Sorry. Ich hatte übersehen, das Du solche schon benutzt:
...$=msi...
Hi,
...$=msi...
jaja trotzdem lag dort der Fehler, da m und s sich aufheben ;)
<peinlich peinlich>
Aber jetzt kommts: s bedeutet, der string wird zeilenweise durchgegangen (was ich möglichst nicht will) aber bei m solte eigentlich der gesamte String genommen werden. BEi meinen TEsts erzielten beide aber den gleichen Effekt (natürlich den den ich nicht möchte)
das verstehe ich nicht wirklich...
ciao
romy
Hello again,
was ich nicht so ganz verstehe, ist das Suchmuster:
$pattern = '=^(.*)<a(.*)href="?(\S+)"([^>]*)>(.*)</a>(.*)$=msi';
Bist Du Dir denn im Klaren darüber, was da genau passiert? Ein Denkfehler? Vielleicht durchblicke ich es auch gar nicht, weil ich Dein Problem nicht verstanden habe... 8|
msi
...was ja bedeuten würde, das bei dem ersten gefunden Muster bereits der komplette String maskiert wird. Dadurch kommt doch jetzt immer das gleiche Ergebnis zustande, oder?
Hi,
was ich nicht so ganz verstehe, ist das Suchmuster:
$pattern = '=^(.*)<a(.*)href="?(\S+)"([^>]*)>(.*)</a>(.*)$=msi';
Bist Du Dir denn im Klaren darüber, was da genau passiert?
nur zur Hälfte leider...
=
^ <= Stringanfang
(.*) <= wozu diesen Teil Zwischenspeichern?
<a
(.*)
href
=
"?
(\S+)
" <= fehlt hier nicht auch ein Fragezeichen?
ja, stimmt ich sehe es auch
([^>]*)
>
(.*)
</a>
(.*) <= und wozu das, es gehört doch nicht mehr zum Link?
$ <= Stringendemsi
ich dachte (.*) sagt aus, egal was dort steht suche trotzdem nach <a
Also das sozusagen beliebiger Text vor und nach dem link stehen kann.
Wenn ich dies weglasse, wie kann ich dann den neuen STring wieder richtig zusammensetzen?
Ich gebe mal ein Beispiel:
bla
böla
bla
<a href="bla"> bla </a>
<a href="bla"> bla </a>
<a href="bla"> bla </a>
<gihf
asdfj
asdlf
nach der Ersetzung sollte das Ganze so aussehen:
bla
böla
bla
<a href="bla?anderesbla=js&..."> bla </a>
<a href="bla?anderesbla=js&..."> bla </a>
<a href="bla?anderesbla=js&..."> bla </a>
<gihf
asdfj
asdlf
ausserdem brauche ich auch die targets, denn diese müssen sofern vorhanden auch mit in der querystring!
?
vielen Dank für deine Mühen...
ciao
romy
ich dachte (.*) sagt aus, egal was dort steht suche trotzdem nach <a Also das sozusagen beliebiger Text vor und nach dem link stehen kann.
Korrekt, das bewirkt .*
Und durch die Klammer wird dieser Teil dann für spätere Zugriffe intern zwischengespeichert.
Durch das Weglassen der Klammer kannst Du den neuen String nicht wieder zusammensetzen, weil Dir der Teil vor dem Link fehlt. Okay, das leuchtet ein.
Ich überlege mir mal, ob man unbedingt die Teile vor und nach dem Link extrahieren muß oder ob es nicht auch irgendwie anders geht...
Bis später
Hi,
Durch das Weglassen der Klammer kannst Du den neuen String nicht wieder zusammensetzen, weil Dir der Teil vor dem Link fehlt. Okay, das leuchtet ein.
Ich überlege mir mal, ob man unbedingt die Teile vor und nach dem Link extrahieren muß oder ob es nicht auch irgendwie anders geht...
danke, das wäre echt nett
Hätte noch ein großes Problem:
Ich muss damit rechenen, das links zB. so
eingeben werden
href = "bla"
href=bla
href= "bla"
href=" bla "
Immer wenn Leerzeichen auftreten funktioniert diese suche nicht mehr, was und wo muss ich einfügen um es korrekt funktionieren zu lassen?
bzw.
wenn dort steht
class="blA" target="bla" border="3"
hab ich eigentlich ne Möglichkeit gefunden, den Target zu extrahieren /(aber nur eigentlich ;))
preg_match('/target=(.*)/i',$string,$txt
allerdings liefert dies auch border="3" mit und ich möchte gern das die suche nach dem nächsten leerzeichen abbricht...
danke echt, Du hast mir schon sehr geholfen
ciao
romy
Bitteschön! Okay, ich überleg mir was für möglichst alle Tag-Varianten von Kombinationen mit Zeilenwechseln, Leer- und Anführungszeichen... Das kann allerdings ein paar Tage dauern.
Eine Lösung für solche Fälle brauche ich wohl früher oder später selbst mal. Ich plane nämlich eine Art zentrale Link-Liste, wobei in (X)HTML nur eine Referenz darauf als XML-Tag im Code stehen soll, z.B. <a refid="foo"></a>. Mit PHP sollen dann anhand der ID zur Laufzeit Attribute wie href und target aus einem zentralen Array eingefügt werden. Das spart Verwaltungsarbeit.
Gruß
Danny
Hier mal ein möglicher Ansatz, wobei man sich die Teile vor und Nach dem Link nicht zu merken braucht, da das von den RegExp intern geregelt wird.
An die Funktion parse_links werden gültige Links übergeben und können manipuliert werden. Nach der Rückgabe erfolgt die Ersetzung im String automatisch...
<?php
function setLink($file)
{
if (file_exists($file)) {
$file_string = implode("", (@file($file)) );
$pattern = '/(<a.*>.*</a>)/me'; // e = Ersetzung mit eigener PHP-Funktion
$matches = preg_replace($pattern, 'parse_link("\1")', $file_string);
print_array($matches);
}
else {
return 0;
}
}
function parse_link($link)
{
return $link."<br />";
}
function print_array($var)
{
print "<textarea style="width: 950px; height:550px;">";
print_r ($var);
print "</textarea>";
}
setLink("test.html");
?>
Hi,
Hier mal ein möglicher Ansatz, wobei man sich die Teile vor und Nach dem Link nicht zu merken braucht, da das von den RegExp intern geregelt wird.
danke schon mal ich fand dies auf jeden Fall schon mal übersichtlicher, als meine Variante, im Moment tut es allerdings das Gleiche: d.h. das mit dem Umbruch ist wahrscheinlich ganz schön hart...
ich liege Dir zu Füssen ... ;)
ciao
romy
Hi Romy,
den Text hast Du Dir selbst überschrieben, weil Du in der Callback-Funktion 1 zurückgegeben hast. Dies wird an das Echo weitergeleitet...
Matches ist ein Array, das die gefundenen Teilmuster enthält. Und so mußt Du es auch behandeln.
Gruß,
Danny
Hi,
den Text hast Du Dir selbst überschrieben, weil Du in der Callback-Funktion 1 zurückgegeben hast. Dies wird an das Echo weitergeleitet...
Matches ist ein Array, das die gefundenen Teilmuster enthält. Und so mußt Du es auch behandeln.
I know I know ;)
Bin auch schon drauf gekommen, ich muss natürlich den text, davor und danach wieder einsetzen...
Leider waren dies nur die Problemchen...
Ich könnte ja auch den Code zeilenweise einlesen und auch zeilenweise ersetzen, bloss was mache ich mit sowas:
<a
href=hasdj>dgf
</a>
dann ist es ja nicht mehr in einer Zeile...
*quengel*
ciao
romy