Für Highlightfunktion Text aus HTML ausfiltern

Funky_MF

Erfahrenes Mitglied
Um eine Suchfunktion innerhalb einer Website übersichtlicher zu gestalten, möchte ich alle gefundenen Suchbegriffe im Suchergebnis highlighten, so wie es z.B. auch hier im Board gemacht wird.

Die Daten in denen gesucht wird, liegen als HTML-Code in einer MySqL-DB, die Abfrage mit der Suchfunktiion klappt auch wunderbar und bis jetzt benutze ich folgende Zeilen für die Highlightfunktion. Der Suchbegriff wird als Variable $search übergeben und das Suchergebnis, also der komplette HTML-Block des zugehörigen Datensatzes als Array-Element $content [1]:
PHP:
$content[1] = str_replace(strtolower($search), "<span style=\"color:#FFF; background-color:#00A973; border:1px solid #FFF; padding:1px;\">".strtolower($search)."</span>", $content[1]);
 $content[1] = str_replace(strtoupper($search), "<span style=\"color:#FFF; background-color:#00A973; border:1px solid #FFF; padding:1px;\">".strtoupper($search)."</span>", $content[1]);
 $content[1] = str_replace(ucfirst($search), "<span style=\"color:#FFF; background-color:#00A973; border:1px solid #FFF; padding:1px;\">".ucfirst($search)."</span>", $content[1]);

echo $content[1];

Funktioniert soweit ganz gut, wenn aber jetzt als Suchbegriff z.B. 'span' oder irgendein anderer HTML-spezifischer Begriff übergeben wird, dann zerhauts logischerweise den HTML-Code an der entsprechenden Stelle.
Ich müsste also zunächst alle HTML-Tags rausfiltern, die Highlightfunktion anwenden, und danach die HTML-Tags wieder einfügen, an der richtigen Stelle natürlich.
Mein erster Gedanke war, mit explode zu arbeiten und als Trennzeichen '<' bzw. '>' zu verwenden, aber dann hab ich zwar alles in einem Array, aber kann nicht mehr zw. HTML u. Text unterscheiden.

Wie kann ich das lösen ?
 
Zuletzt bearbeitet:
Genau, wie bei Deinem gleichen Problem im Query, sind auch hier reguläre Ausdrücke die Lösung, z.B. mit [phpf]preg_replace[/phpf].

Gruß hpvw
 
Ich habe zu einem verwandten Thema einen Beitrag mit einem hilfreichen Algorithmus geschrieben.
Für deine Wünsche muss er jedoch etwas erweitert werden und hab’ kurzerhand eine kleine, bescheidene PHP-4-Klasse daraus gemacht:
PHP:
<?php

	class HighlightSearchterms
	{

		var $searchterms;
		var $string;
		var $excludedTags;
		var $classCount;
		var $_matches;

		function highlightSearchterms()
		{
			$this->searchterms	= array();
			$this->string		= '';
			$this->excludedTags	= array( 'style', 'script' );
			$this->classCount	= 10;
			$this->_matches		= array();
		}

		function setSearchterms($searchterms)
		{
			if( !is_array($searchterms) ) {
				return false;
			}
			return $this->searchterms = $searchterms;
		}

		function setString($string)
		{
			if( !is_string($string) ) {
				return false;
			}
			return $this->string = $string;
		}

		function setExcludedTags($excludedTags)
		{
			if( !is_array($excludedTags) ) {
				return false;
			}
			return $this->excludedTags = $excludedTags;
		}

		function setClassCount($classCount)
		{
			if( !is_int($classCount) ) {
				return false;
			}
			return $this->classCount = $classCount;
		}

		function _setHighlightClass($searchterm)
		{
			$found = false;
			if( !in_array(strtolower($searchterm), array_map('strtolower', $this->searchterms)) ) {
				return false;
			}
			foreach( $this->_matches as $key => $value ) {
				if( strtolower($searchterm) == strtolower($value) ) {
					$found = true;
					break;
				}
			}
			if( $found === false ) {
				foreach( $this->searchterms as $key => $value ) {
					if( strtolower($searchterm) == strtolower($value) ) {
						$key = count($this->_matches);
						$this->_matches[] = $searchterm;
						break;
					}
				}
			}
			return '<strong class="highlight-'.($key%$this->classCount).'">'.$searchterm.'</strong>';
		}

		function getHighlightedString()
		{
			$output = '';
			$boundary = md5(uniqid());
			$pattern = '/(<[\/]*?[^<>]*?>)([^<]*)/is';
			preg_match_all($pattern, '<'.$boundary.'>'.$this->string.'</'.$boundary.'>', $matches);

			for( $i=0; $i<count($matches[0]); $i++ ) {
				if( preg_match('/<\s*(?:'.join('|', array_map('preg_quote', $this->excludedTags)).')/is', $matches[0][$i]) ) {
					$output .= $matches[0][$i];
				} else {
					$output .= $matches[1][$i];
					$output .= preg_replace('/(?<=^|\W)('.join('|', array_map('preg_quote', $this->searchterms)).')(?=\W|$)/ise', '$this->_setHighlightClass("\1")', $matches[2][$i]);
				}
			}
			return preg_replace('|^<'.$boundary.'>(.*)</'.$boundary.'>$|is', '\1', $output);
		}

	}


/*

	$searchterms = array(
		'lorem',
		'Ipsum',
		'SpaN',
		'cLaSs='
	);
	$string = 'Lorem <!-- ipsum --> span class= <span class="lorem">dolor</span> …';

	$foobar = new HighlightSearchterms();
	$foobar->setSearchterms($searchterms);
	$foobar->setString($string);

	echo '<pre>'.htmlspecialchars($foobar->getHighlightedString()).'</pre>';

/**/

?>
Leider ist sie bisher unkommentiert. Das heißt, du müsstest dir dessen Funktionsweise selbst herausfriemeln, falls du sie wissen möchtest.
 
Hier mal ein Beispiel mit den gleichen regulären Ausdrücken und Texten wie im anderen Thread für das Query:
PHP:
<?
$strings=array(
    '<html>bla suchbegriff bla</html>',
    'bla suchbegriff bla<tag>blub foo</tag> bla',
    'bla bla<tag>blub foo</tag> bla suchbegriff',
    'bla bla<tag>blub suchbegriff foo</tag> bla',
    'bla <tag attrib="suchbegriff">blub foo</tag> bla suchbegriff',
    'bla bla <tag attrib="suchbegriff">blub foo</tag> bla',
    'bla <tag suchbegriff="value">blub foo</tag> bla suchbegriff',
    'bla bla<tag suchbegriff="value">blub foo</tag> bla',
    '<html>sb nicht vorhanden</html>',
    'sb nicht vorhanden <tag>hier auch nicht</tag> immer noch nicht');
    
function highlightInHTMLString($text,$high) {
    $h=str_replace('\\','\\\\',$high);
    $h=str_replace('/','\/',$h);
    $h=str_replace('*','\*',$h);
    $h=str_replace('.','\.',$h);
    //weitere reg-ex-sonderzeichen ersetzen
    
    $r=preg_replace('/(>[^<]*)('.$h.')/', '$1<strong>$2</strong>',$text);

    $r=preg_replace('/^([^<]*)('.$h.')/', '$1<strong>$2</strong>',$r);
    return $r;
}

foreach ($strings as $s) {
    echo "\n<br>\n";
    echo $s;
    echo "\n<br>\n";
    echo highlightInHTMLString($s,'suchbegriff');
    echo "\n<br>\n";
}
?>
Gruß hpvw
 
@all: Erstmal Danke für die Vorschläge, hatte leider noch kein Zeit sie zu auszuprobieren, werd ich im Laufe des morgigen Tages tun.

@hpvw: Hatte leider in den MySQL-Thread nicht mehr reingeschaut seit der "Moralpredigt" von DealeyLama ;), und hab grad festgestellt, daß ich ein Problem hatte mit der Benachrichtigung bei neuen Antworten auf Threads. Aber werde mir jetzt beide Lösungen mal genau vornehmen und mich dann wieder melden. Danke schonmal für beide Lösungsvorschläge.

@Gawayn: Nicht so voreilig mit deinen Verurteilungen, du kannst dir sicher sein, ich kenn das Manual und speziell die String-Referenzen hab ich längst durchgekaut, allerdings bin ich kein Profi, deshalb ist mir eben auch nicht immer alles ganz klar was da steht, und bin echt dankbar für Leute, die mir hier ihre Hilfe anbieten. ;
 
@hpvw: Super, vielen Dank, hab jetzt deine beiden Lösungen kombiniert, also zuerst bei der Suche in der DB und dann beim Highlighten, funktioniert einwandfrei, ich wußte ja, daß es irgendwas mit RegEx sein muß, aber auf die Lösung wäre ich selber nicht gekommen.
:) :) :)

@Gumbo: Deine Lösung hab ich jetzt nicht mehr getestet, aber habs mir mal gespeichert.
 
Zurück