Ersetzen ohne HTML zu zerstören

September 2009

Etwas zu ersetzen oder hervorzuheben ohne den HTML-Code zu zerstören ist nicht ganz so einfach. Mit ein bisschen Regex funktioniert es dennoch.

Im folgenden Beispiel wird die Zeichenfolge "spa" hervorgehoben (fett geschrieben), ohne den <span>-Tag zu beeinflussen.
<?php
$text 
'Ich suche spanisches <span style="color:#ff0;">Geld</span>!';

$gesucht 'spa'// der gesuchte String
$links '<b>'// linker Begrenzer
$rechts '</b>'// rechter Begrenzer

$links_Q preg_quote($links'#');
$rechts_Q preg_quote($rechts'#');
$gesucht_Q preg_quote($gesucht'#');

while(
preg_match('#(>|^)[^<]*(?<!'.$links_Q.')'.$gesucht_Q.'(?!'.$rechts_Q.')[^>]*(<|$)#isU'$text)) // damit auch wirklich alles ersetzt ist
  
$text preg_replace('#(^[^<]*|>[^<]*)(?<!'.$links_Q.')('.$gesucht_Q.')(?!'.$rechts_Q.')([^>]*<|[^>]*$)#isU''${1}'.$links.'${2}'.$rechts.'${3}'$text);

echo 
$text;
# Ich suche <b>spa</b>nisches <span style="color:#ff0;">Geld</span>!
?>
Mit diesen Regex wird überprüft, ob sich der gesuchte String nicht zwischen < und > befindet, bzw. ob er ausserhalb eines HTML-Tags steht. Ebenfalls wird mit Look-Around-Assertions kontrolliert, dass das Suchwort nicht bereits verarbeitet worden ist, da das Skript sonst in einer Endlosschleife enden würde, weil derselbe String mehrmals (unendlich Mal) verarbeitet werden würde.

Im nächsten Beispiel wird ein Zeichen ersetzt.
<?php
$text 
'Ich suche spanisches <span style="color:#00f;">Geld</span>!';

$gesucht 's'// das gesuchte Zeichen oder Zeichenfolge
$ersetzt '$'// das ersetzte Zeichen oder Zeichenfolge

while(preg_match('#(>|^)[^<]*'.preg_quote($gesucht,'#').'[^>]*(<|$)#isU'$text))
  
$text preg_replace('#(>[^<]*|^[^<]*)'.preg_quote($gesucht,'#').'([^>]*<|[^>]*$)#isU''${1}'.$ersetzt.'${2}'$text);

echo 
$text;
# Ich $uche $pani$che$ <span style="color:#ff0;">Geld</span>!
?>
Hier darf der String $gesucht nicht in $ersetzt vorkommen, weil daraus unmittelbar eine Endlosschleife zur Folge hätte.

Nach diesem Prinzip lassen sich auch andere Sachen machen, beispielsweise einen Text in Leetspeak übersetzen:
<?php
$text 
'Ich kann das <strong>nicht</strong> lesen.';

$leets = array('a'=>'4','b'=>'8','c'=>'©','d'=>'Ð','e'=>'3','f'=>'ƒ','g'=>'6',
               
'h'=>'#','i'=>'!','j'=>'_|','k'=>'&#75;','l'=>'1','m'=>'&#77;',
               
'n'=>'&#78;','o'=>'0','p'=>'|°','q'=>'0_','r'=>'|2','s'=>'5','t'=>'7',
               
'u'=>'µ','v'=>'\/','w'=>'&#87;','x'=>'%','y'=>'¥','z'=>'2');

foreach(
$leets as $orig => $leet)
  while(
preg_match('#(>|^)[^<]*'.$orig.'[^>]*(<|$)#isU'$text))
    
$text preg_replace('#(>[^<]*|^[^<]*)'.$orig.'([^>]*<|[^>]*$)#isU''${1}'.$leet.'${2}'$text);

$text str_replace(array('&#75;','&#77;','&#78;','&#87;'), array('K','M','N','W'), $text);
/* Vier Buchstaben sollten nur in Grossschreibung umgewandelt, jedoch nicht
   ersetzt werden. Allerdings mussten die entsprechenden Enitites verwendet 
   werden, da sonst auch hier eine Endlosschleife entstehen würde. */

echo $text;
# !©# K4NN Ð45 <strong>N!©#7</strong> 1353N.
?>

Siehe auch:
 


Andere Einträge