baksyl
baksyl

Reputation: 67

multi-word search and replace in array of arrays

This code belongs to a search function. A user can enter $search_string and the code below will put html around the string to highlight it. Search has been expanded to include multi-word searches (if you search 'ifs ands' it will only show results with both of those words).

It searches through an array of arrays and the nested array contain fields that we search through: Overview, procedure and verification. It then finds the values in the array and highlights the words you've searched for.

foreach ($results as $s_result => $row) {
    $results[$s_result]['overview'] = str_ireplace($search_string, "<span style=\"background-color: #ff0;\">$search_string</span>", htmlspecialchars($row['overview']));
    $results[$s_result]['execution'] = str_ireplace($search_string, "<span style=\"background-color: #ff0;\">$search_string</span>", htmlspecialchars($row['execution']));
    $results[$s_result]['verification'] = str_ireplace($search_string, "<span style=\"background-color: #ff0;\">$search_string</span>", htmlspecialchars($row['verification']));
}

WITHOUT having to iterate through the array of arrays multiple times for each search keyword, how can I highlight multiple words/keywords the user enters in one pass? There might not be a way but I cant easily come to that conclusion.

Upvotes: 0

Views: 97

Answers (1)

miken32
miken32

Reputation: 42694

str_replace can take an array as a subject so this should work:

foreach ($results as &$row) {
    $row = str_ireplace(
        $search_string,
        "<span class=\"highlight\">$search_string</span>",
        array_map("htmlspecialchars", $row)
    );
}

Note we’re changing $row by reference, so when you iterate over $results it will show the changes.

Of course you’re not accounting for substrings and such, so a regular expression might be better suited for this:

foreach ($results as &$row) {
    $row = preg_replace(
        "/\\b($search_string)\\b/i",
        "<span class=\"highlight\">$1</span>",
        array_map("htmlspecialchars", $row)
    );
}

Finally, if you really want to get rid of the foreach loop you can use array_walk with an inline function, although I'm not sure how much faster it actually is – it's quite possible it uses the same calls as a foreach loop when you get down to the C code.

array_walk($results, function(&$v, $k) use($search_string) {
    $v = preg_replace(
        "/\\b($search_string)\\b/i",
        "<span class=\"highlight\">$1</span>",
        array_map("htmlspecialchars", $v)
    );
});

Tested with sample input:

$search_string = "foobar";
$results = [
    ["overview"=>"some fobar text", "execution"=>"some foobr text", "verification"=>"some foobar text"],
    ["overview"=>"some fbar text", "execution"=>"some fobr text", "verification"=>"some foobarbaz text"],
];

Upvotes: 1

Related Questions