RSS Feed

Php suchen ersetzen und HTML-Tags erhalten

03.04.2009 by naden

PHP hat so einige Funktion zum suchen und ersetzen von Textstrings mit und ohne die Hilfe von regulärer Ausdrücken. Hat man die nötige Geduld und das Wissen, kann man damit fast alles “klären und säubern”.

In Blogartikeln, die HTML wie Links und Bilder enthalten, wollte ich zusätzliche Links einparsen die mit bestimmten Keywords verknüpft sind.

Das Problem, was ich mit einem regulären Ausdruck nicht lösen konnte ist, dass auch Keywords innerhalb von Attributen wie title=”Keyword”, <img src=”…/keyword/…” /> oder <a href=”">Keyword</a> etc. ersetzte wurden.

Meine Lösung arbeitet mit zwei regulären Ausdrücken. Erst wird der Text an den HTML-Tags in Tokens zerlegt. Diese Tokens werden durchlaufen. Befindet sich der Algorithmus innerhalb eines HTML-Tags, so werden gefundene Keywords ignoriert. Ansonsten ersetzt.

Da der Text zwingend xml-konform sein muss, werden zuerst HTML-Short-Tags wie <img> und <br> in valides XML umgeformt. Dies wird ganz am Ende des Parsers wieder rückgängig gemacht.

Bei sehr schlechtem HTML lohnt sich eventuell der Einsatz von tidy_clean_repair.

/**
 * Suchen und ersetzen von Strings wobei HTML-Tags beachtet werden.
 * @param string $search zu suchender string oder callback function
 * @param string $replace zu ersetzender string
 * @param string $buffer zu durchsuchende Zeichenkette
 * @param boolean $ic ignoriere Schreibweise, default true
 * @return string
 */
function replace( $search, $replace, $buffer, $ic = true )
{
  /**
   * wandle short-tags um, erleichtert das Parsen
   * <img /> => <img />, <br /> => <br />
   */
  $buffer = preg_replace( '/<img ([^/>]+)(.*)( ?\/?)>/iU', '<img \\1\\2/>', $buffer );
  $buffer = preg_replace( '/<br ( ?)(.?)/>/iU', '<br />', $buffer );
 
  /**
   * matche alle html-tags
   */
  preg_match_all( '/(< [^>]+>|[^< ]+)/i', $buffer, $tokens );
  /**
   * durchlaufe gefundene blöcke
   */
  if( count( $tokens[ 0 ] ) > 0 )
  {
    $result = '';
 
    $depth = 0;
 
    foreach( $tokens[ 0 ] as $token )
    {
      /**
       * überprüfe ob wir innerhalb eines <img /> oder <a> tags sind
       */
      if( $token[ 0 ] == '< ' || $depth != 0 )
      {
        $data .= $token;
        /**
         * tag wird geöffnet
         */
        if( substr( $token, 0, 5 ) == '<img ' || substr( $token, 0, 3 ) == '<a ' )
        {
          $depth ++;
        }
        /**
         * tag wird geschlossen
         */
        elseif( $token == '</img>' || $token == '</a>' )
        {
          $depth --;
        }
      }
      else
      {
        /**
         * eigentlichen string suchen ...
         */
        preg_match_all( '/\b' . $search . '\b/' . ( $ic ? 'i' : '' ) , $token, $matches );
 
        if( count( $matches[ 0 ] ) > 0 )
        {
          foreach( $matches[ 0 ] as $match )
          {
            /**
             * ... und ersetzen, callback möglich
             */
            $token = preg_replace( "/$match/", is_callable( $replace ) ? $replace( $match ) : $replace, $token );
          }
        }
        $data .= $token;
      }
    }
 
    $buffer = $data;
 
    unset( $data );
  }
 
  /**
   * wandle anfangs geänderte html tags zurück
   */
  $buffer = str_replace( array( '>', '<br />' ), array( ' />', '<br />' ), $buffer );
 
  return( $buffer );
}
 
/**
 * test
 */
$buffer = '<p><img src="/teststring" title="Titel: Ein TestString" alt="Bild: TestString" /> dieser TestString wird ersetzte.<br /><strong>dieser TestString auch</strong> <a href="" title="Ziel TestString">hier geht es zu TestString</a>.</p>';
 
/**
 * replace
 */
$buffer = replace( 'teststring', '<a href="">Gefunden</a>', $buffer );
 
/**
 * replace mit callback
 */
$buffer = replace( 'teststring', create_function( '$s', 'return( strtoupper( $s ) );' ), $buffer );
 
print( $buffer );

Download

Verbesserungsvorschläge sind willkommen!


5 Kommentare »

  1. Adam sagt:

    Vielen Dank für diese wunderbare Funktion! Genau was ich gesucht habe – funktioniert einwandfrei :-)

  2. Adam sagt:

    Nachtrag: ich würde vielleicht auch noch die Shorttags ‘input’ und ‘hr’ umwandeln…

  3. naden sagt:

    Macht Sinn. Ich werde das die Tage etwas anpassen.

  4. cusaro sagt:

    Vielen Dank für die Funktion. Danach habe ich sehr lange gesucht.

  5. naden sagt:

    @cusaro deine Anfänglichen Probleme hängen mit dem hie rim BLog verwendeten Syntax-Highlighter zusammen. Das ist leider noch immer ein komplexes Thema.

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

*

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>