Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Better Highlight Function 1

Status
Not open for further replies.

solepixel

Programmer
May 30, 2007
111
US
Can someone take a look at this highlight function? It works pretty good, but I'd like to know how to tweak it so that it:

1. highlights an entire phrase (it already does this)
2. highlights each individual word
3. does not mess up words inside <html> tags

Code:
function highlight($haystack,$needle){
	$h = strtoupper($haystack);
	$n = strtoupper($needle);
	$pos = strpos($h,$n);
	if ($pos !== false) {
		$var = substr($haystack,0,$pos).'<span class="highlight"><strong>'.substr($haystack,$pos,strlen($needle)).'</strong></span>';
		$var .= substr($haystack,($pos+strlen($needle)));
		$haystack = $var;
	}
	return $haystack;
}
 
what do you actually want it to do? highlight all occurrences of whatever the needle might be?
 
yes, but in addition, all individual words. so if the needle has a space, then explode it and highlight all occurances of each individual word. But I think the entire phrase should be done first, so the words don't look broken up.
 
it's a bit ugly but try this. whole string matches are highlighted in a different colour to word only matches.

the use of the $GLOBALS variable is to maintain the original case of the match whilst still making the algorithm case insensitive.

Code:
<?php 
function highlight($needle, $haystack){
	$needle = trim($needle);
	//build pattern
	$pattern = str_replace(" ", "\s*", $needle);
	$haystack = preg_replace_callback('/\b('.$pattern.')\b/ims', 'tmpReplace', $haystack);

	
	$_words = explode (" ", $needle);
	foreach($_words as $word){
		$__words[] = '/\b('.$word.')\b/ims';
		$replace[] = "<span class=\"wordMatch\">$1</span>";
	}
	$haystack = preg_replace($__words, $replace, $haystack);
	$haystack = str_replace($GLOBALS['x'], $GLOBALS['y'], $haystack);
	return $haystack;
}
function tmpReplace($match){
	$tmp = md5(uniqid("tmp", true));
	$GLOBALS['x'][] = $tmp;
	$GLOBALS['y'][] = "<span class=\"phraseMatch\">".$match[1]."</span>";
	return $tmp;
}

$text = file_get_contents("[URL unfurl="true"]http://www.ustreas.gov/offices/enforcement/ofac/sdn/sdnlist.txt");[/URL]
echo <<<HTML
<style>
.wordMatch {background-color: red;}
.phraseMatch {background-color: green;}
</style>

HTML
.highlight('bin laden', $text);
?>
 
Hey, i got a chance to try this out today. It seems to replace all the text in the haystack with the needle.
 
ok, wow, i did try this all by itself and it seemed to work great. what am I doing wrong? maybe the needle/haystack are opposite in your function as they are mine. lemme check that.
 
Rock n Roll! That is awesome. Thanks jpadie! Way to go!
 
if the file does not get updated too often, it's a better idea to cache it locally.

i've put this code up on a test server (projects.adieandco.com/randomtests/highlight.php) and it runs pretty quickly.

a very simple enhancement you could consider is building a table of contents (so to speak) whereby you would create anchors throughout the text at each match, and then plot the matches as links at the top of the file.

Code:
<?php
function highlight($needle, $haystack){
    $needle = trim($needle);
    //build pattern
    $pattern = str_replace(" ", "\s*", $needle);
    $haystack = preg_replace_callback('/\b('.$pattern.')\b/ims', 'tmpReplace', $haystack);

    
    $_words = explode (" ", $needle);
    foreach($_words as $word){
        $__words[] = '/\b('.$word.')\b/ims';
        $replace[] = "<span class=\"wordMatch\">$1</span>";
    }
    $haystack = preg_replace($__words, $replace, $haystack);
    $haystack = str_replace($GLOBALS['x'], $GLOBALS['y'], $haystack);
    return $haystack;
}
function tmpReplace($match){
    $tmp = md5(uniqid("tmp", true));
    $GLOBALS['x'][] = $tmp;
    $GLOBALS['y'][] = "<span class=\"phraseMatch\">".$match[1]."</span>";
    return $tmp;
}

$t = isset($_POST['searchtext']) ? trim ($_POST['searchtext']) : '';

echo <<<HTML
<style>
.wordMatch {background-color: red;}
.phraseMatch {background-color: green;}
#static {position: absolute;}
#nonstatic {width:100%; overflow:auto; margin-top: 100px; height: 600px;}
</style>

<form action="{$_SERVER['PHP_SELF']}" method="post">
Search text: <input type="text" name="searchtext" value="$t" /><br/>
<input type="submit" name="submit" value="Highlight Text"/>
</form>
<hr/>
<pre>


HTML;
if (!empty($t)){
	if ( (!file_exists('largetext.txt')) || (filemtime('largetext.txt') < strtotime('-1 day')) ){
		$text = file_get_contents("[URL unfurl="true"]http://www.ustreas.gov/offices/enforcement/ofac/sdn/sdnlist.txt");[/URL]
		$fh = fopen('largetext.txt', "w");
		fwrite($fh, $text, strlen($text));
		fclose ($fh);
	}
	if (empty($text)){
		$text = file_get_contents('largetext.txt');
	}
	echo highlight($t, &$text) . "</pre>";
}
?>
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top