Reputation: 1564
For testing purposes I've stored in database name of colors which are:
Apple green
Banana yellow
Brick red
Charcoal
Coffee
And I created functions to search and display results with using $_GET
and address bar, so far it all works perfectly. So for example if I type to the search form this: ap le ee
My address bar looks like this:
http://test.com/file.php?keywords=ap+le+ee
and my result is obviously Apple green
If I type this: c o
or co
My result is: Charcoal
and Coffee
At this point I want to upgrade this search engine and highlight in result only those parts that matches with provided keywords so what I want to achieve is this:
If I type: app ee
I want to have in result something like this: <strong>App</strong>le gr<strong>ee</strong>n
and I don't have any idea how to achieve it.
I call my results like this:
$colors = get_colors(isset($_GET['keywords']) ? $_GET['keywords'] : null);
foreach($colors as $color) {
echo $color['color_name'] . '<br />';
}
If anyone could help me do it, I'll be very grateful, thank you in advance :)
---EDIT--- 10.03.2014 08:34
This is now the code im using:
$colors = get_colors(isset($_GET['keywords']) ? $_GET['keywords'] : null);
foreach($colors as $color) {
$output = $color['color_name'];
foreach (explode(' ', $_GET['keywords']) as $term)
$output = preg_replace('/(?![^<>]*>)'.preg_quote($term,"/").'/i', '<span style="color:red;">$0</span>', $output);
echo $output . "<br />";
}
Things that work perfect (testing case Banana yellow
, Charcoal
):
doesnt matter if i type l o
or o l
both of those will highlight properly in testing cases.
script doesnt fail if i type last letter, i can type ban w
and it will properly return highlighted Banana yellow
.
The only thing that doesnt work in it is:
bana nana
it highlights only bana
in Banana yellow
So i believe that right now im looking for solution for overlaping terms to work together that if i type bri ick
it should highlight all Brick
in Brick red
instead of only Bri
.
Anyone with ideas how to sort that?
Upvotes: 1
Views: 353
Reputation:
Using @Utkanos suggestion:
foreach($colors as $color) {
$output = $color['color_name'];
foreach(explode(' ', $_GET['keywords']) as $term)
$output = preg_replace('/('.$term.')(?![^>]*>)/i', '<strong>$1</strong>', $output);
echo $output .'<br />';
}
You want the result from the preg_match
to replace the $term
.
Sorry, it's a lot of code for a apparently "simply" problem, but this should do, what you expect:
$colors = array("Apple green",
"Banana yellow",
"Brick red",
"Charcoal",
"Coffee",
"Fire red");
$terms = "re e";
$output = "";
foreach($colors as $color) {
$output = $color;
$words = array();
foreach(explode(' ', $terms) as $term) {
$match = preg_match_all("/(". $term .")/i", $output, $hits, PREG_OFFSET_CAPTURE);
if($match) {
$positions = array();
foreach($hits[1] as $hit) {
for($i = $hit[1]; $i < strlen($hit[0]) + $hit[1]; $i++) {
$positions[] = $i;
}
$words[] = array($hits[0][0][0], $positions);
}
}
}
$positions = array();
foreach($words as $word) {
foreach($word[1] as $position)
$positions[] = $position;
}
$positions = array_unique($positions);
asort($positions);
$positions = array_values($positions);
if(count($positions) > 0) {
$offset = 0;
$open = false;
$closed = true;
$i = $positions[0];
foreach($positions as $value) {
if($value != $i AND !$closed) {
$output = substr_replace($output, "</strong>", $i + $offset, 0);
$offset += 9;
$open = false;
$closed = true;
$i = $value;
}
if(!$open AND $closed) {
$output = substr_replace($output, "<strong>", $value + $offset, 0);
$offset += 8;
$open = true;
$closed = false;
}
$i++;
}
if(!$closed)
$output = substr_replace($output, "</strong>", $positions[count($positions)-1] + $offset +1, 0);
}
echo $output ."<br/>";
}
Upvotes: 1
Reputation: 34556
By the look of it you're allowing multiple search terms, separated by space. So I'd loop over the terms and do a replace on the colour before output.
foreach($colors as $color) {
$output = $color['color_name'];
foreach(explode(' ', $_GET['keywords']) as $term)
$output = preg_replace('/'.$term.'(?![^>]*>)/i', '<strong>'.$term.'</strong>', $output);
echo preg_replace('/And\b/', 'and', ucwords($output)).'<br />';
}
Upvotes: 3