Anzeige

preg_replace durch preg_replace_callback ersetzen


#1
Hallo liebe User!

Bei unserer Website steht die Umstellung auf PHP 7 an - wird ja auch endlich Zeit. ;-)

Allerdings stoße ich dabei auf das Problem, dass ich die Funktion "preg_replace" (aufgrund /e) nicht erfolgreich ersetzen kann und hoffe, ihr könnt mir an dieser Stelle weiterhelfen.
Ich habe es bereits erfolglos mit verschiedenen Varianten zu preg_replace_callback und preg_replace_callback_array versucht.

PHP:
$patterns_anywhere = Array(
        '/\<!-- (.*?) -->/'=>'', // comment
        '/\&lt;br \/&gt;/'=>'<br />', // explicit line break
        '/\[\[Image:(.+?)\|([0-9]*)\|([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})\]\]/e'=>"showimage('\\1', '\\3', '\\2')", // specific image revision
        '/\[\[Image:(.+?)\|([0-9]+)\]\]/e'=>"showimage('\\1', '', '\\2')", // image with specific width
        '/\[\[Image:(.+?)\]\]/e'=>"showimage('\\1')", // image
        '/\[\[(:[^\|\]]*?)\|([^\]]+?)\]\]/e'=>"'<a href=\"' . wikilink('\\1') . '\">\\2</a>'", // link to category
        '/\[\[(:[^\|\]]*?)\]\]/e'=>"'<a href=\"' . wikilink('\\1') . '\">\\1</a>'", // link to category
        '/\[\[([^\|\]]+?)\|([^\]]+?)\]\]/e'=>"'<a title=\"%linkstart%\\1%linkend%\" href=\"' . wikilink('\\1') . '\"%class%>\\2</a>'", // link to page
        '/\[\[([^\|\]]+?)\]\]/e'=>"'<a href=\"' . wikilink('\\1') . '\"%class%>%linkstart%\\1%linkend%</a>'", // link to page
        '/\[([^\] ]+) ([^\]]+?)\]/'=>'<a href="\\1">\\2</a>', // external link
        '/\[([^\] ]+?)\]/'=>'<a href="\\1">\\1</a>', // external link
        "/&apos;&apos;&apos;&apos;&apos;(.+?)&apos;&apos;&apos;&apos;&apos;/"=>'<strong><i>\\1</i></strong>', // bold
        "/&apos;&apos;&apos;(.+?)&apos;&apos;&apos;/"=>'<strong>\\1</strong>', // bold
        "/&apos;&apos;(.+?)&apos;&apos;/"=>'<i>\\1</i>', // italic
        '/&lt;u&gt;(.+?)&lt;\/u&gt;/'=>'<u>\\1</u>', // underline
        '/&lt;s&gt;(.+?)&lt;\/s&gt;/'=>'<del>\\1</del>', // strike
        '/&lt;sub&gt;(.+?)&lt;\/sub&gt;/'=>'<sub>\\1</sub>', // subscript
        '/&lt;sup&gt;(.+?)&lt;\/sup&gt;/'=>'<sup>\\1</sup>' // superscript
);
// patterns which will be matched against whole lines
$patterns_lines = Array(
        '/^[\-]{4,}[\s]*$/'=>'<hr class="userline" />', // horizontal line
        '/^====== (.+?) ======[\s]*$/'=>'<h6>\\1</h6>', // heading level 6
        '/^===== (.+?) =====[\s]*$/'=>'<h5>\\1</h5>', // heading level 5
        '/^==== (.+?) ====[\s]*$/'=>'<h4>\\1</h4>', // heading level 4
        '/^=== (.+?) ===[\s]*$/e'=>"'<a id=\"' . make_anchor('\\1') . '\" name=\"' . make_anchor('\\1') . '\"></a><h3>\\1</h3>'", // heading level 3
        '/^== (.+?) ==[\s]*$/e'=>"'<a id=\"' . make_anchor('\\1') . '\" name=\"' . make_anchor('\\1') . '\"></a><h2>\\1</h2>'", // heading level 2
        '/^= (.+?) =[\s]*$/'=>'<h1>\\1</h1>', // heading level 1
);
    
//Code übersprungen

// regular formatting codes (defined in $patterns_anywhere)
foreach ($patterns_anywhere as $search=>$replace) {
    $string = preg_replace($search, $replace, $string, -1, $replace_count);z
    //Code übersprungen
}

//Code übersprungen

// regular formatting codes (defined in $patterns_lines)
$lines = explode("\n", $string);
foreach ($lines as $key=>$line) {
    foreach ($patterns_lines as $search=>$replace) {
        $line = preg_replace($search, $replace, $line);
    }
    $lines[$key] = $line;
}
Ich hoffe, ihr könnt mir weiterhelfen. Vielen Dank im Voraus!

Viele Grüße
Bananenflanke
 

Sempervivum

Erfahrenes Mitglied
#2
Ich habe da etwas ausgearbeitet und hoffe, dass es dein Problem lösen kann:
PHP:
// diese Funktionen nur als Dummys für dein showImage()
function showImage1($a) {
    return 'showImage1 a=' . $a;
}
function showImage3($a, $b, $c) {
    return 'showImage3 a=' . $a . ' b=' . $b . ' c=' . $c;
}

// Erste Variante mit benannten Funktionen:
// function cb1($matches) {return showImage3($matches[1], '', $matches[2]);}
// function cb2($matches) {return showImage1($matches[1]);}
// $patterns_anywhere = [
//     '/\[\[Image:(.+?)\|([0-9]+)\]\]/' => "cb1",
//     '/\[\[Image:(.+?)\]\]/' => "cb2"
// ];

// Zweite Variante mit anonymen Funktionen:
$patterns_anywhere = [
    '/\[\[Image:(.+?)\|([0-9]+)\]\]/' => function ($matches) {return showImage3($matches[1], '', $matches[2]);},
    '/\[\[Image:(.+?)\]\]/' => function ($matches) {return showImage1($matches[1]);}
];

$subject2 = 'xrmhnt[[Image:abc|4711]]oiwhrj[[Image:def|4712]]himnrthotw[[Image:xyz]]';
foreach($patterns_anywhere as $patt => $cb) {
    $subject2 = preg_replace_callback($patt, $cb, $subject2);
}
echo $subject2;
Wie Du siehst, habe ich statt des Ersetzungsstrings jetzt die Callbackfunktionen in das Array eingetragen. Sicherlich kann man das noch auf preg_replace_callback_array() umstellen und das foreach einsparen.
Weil ich nicht wusste, wie deine Funktion showImage() aussieht und weil ich nicht in variable Parameter einsteigen wollte, habe ich zum Testen die zwei Dummyfunktionen showImage1() und showImage3() definiert.
 
Zuletzt bearbeitet:
#3
Hallo Sempervivum,

vielen Dank für deine Mühe!
Wenn ich es richtig sehe, würde das aber nur das "showimage-Problem" beheben, oder?
Wie würde ich denn die neue Callback-Funktion für die restlichen Ersetzungen verwenden?
 

Sempervivum

Erfahrenes Mitglied
#4
Ja, das sollte nur eine Demo sein, wie es im Prinzip funktioniert. Du wirst wohl nicht darum herum kommen, für jede Ersetzung eine eigene Callback-Funktion zu schreiben. Wenn Du erst Mal weißt, wie es funktioniert, ist es ja nur eine Fleißarbeit.
 
#5
Dann habe ich das ja immerhin richtig verstanden. :)

Könntest du mir bitte noch ein Beispiel erstellen, wie es für eine Ersetzung funktionieren würde, die keine Funktion aufruft?
Also beispielswiese für '/^[\-]{4,}[\s]*$/'=>'<hr class="userline" />', // horizontal line
 

Sempervivum

Erfahrenes Mitglied
#6
Gern. Dann müsste es wohl so aussehen:
Code:
$patterns_lines = Array(
    '/^[\-]{4,}[\s]*$/' => function($matches) {return '<hr class="userline" />';}
    // usw.
In dem Fall braucht man den Parameter $matches nicht, weil der gefundene String einfach ausgetauscht wird.
 
#7
Ah, jetzt habe ich das Prinzip glaube ich verstanden.

Allerdings funktioniert das ja nicht, wenn es kein reines Austauschen ist, sondern noch Text dazwischen stehen soll.
Beispiel:
Code:
'/^====== (.+?) ======[\s]*$/'=> function($matches) {return '<h6>\\1</h6>';}, // heading level 6
Muss ich das dann in 2 Teile aufteilen oder gibt es da auch eine elegantere Lösung?
 

Sempervivum

Erfahrenes Mitglied
#8
Dann steht dir der Text ja in $matches zur Verfügung. Sollte dann so funktionieren:
'/^====== (.+?) ======[\s]*$/'=> function($matches) {return '<h6>' . $matches[1] . '</h6>';},
 
Anzeige

Neue Beiträge

Anzeige