Simon
Simon

Reputation: 23141

Wrap whole words AND individual character(s) in HTML tags if contains or matches a search term

I want to add HTML tags to words that contain a search term AND I want to add nested tags around each occurrence of the search term.

Sample string:

$str = "i like programming very much";

Sample search term:

$word = "r";

Desired result:

i like <span class='pice1'>p<span class='pice2'>r</span>og<span class='pice2'>r</span>aming</span> <span class='pice1'>ve<span class='pice2'>r</span>y</span> much

I wrote the following regex for it, but it sometimes doesn't work.

$str = preg_replace(
    "/([^\s{" . preg_quote($word) . "}]*?)(" . preg_quote($word) . ")([^\s{" . preg_quote($word) . "}]*)/siu",
    "<span class='pice1'>$1</span><span class='pice2'>$2</span><span class='pice1'>$3</span>",
    $str
);

Upvotes: -2

Views: 182

Answers (5)

mickmackusa
mickmackusa

Reputation: 47874

To wrap whole words which contain the search term in a given HTML tag, use preg_replace_callback() and have the regex pattern case-insensitively and unicode-safely match zero or more word character before and after the search term.

Once the whole word is isolated, search for the search term again and wrap each occurrence with another HTML tag. str_replace() is not suitable for this inner replacement because it will not preserve the case of the matched search term.

Code: (Demo)

<style>
    .whole_word {color: blue;}
    .sub_word {color: red;}
</style>

<?php

$str = 'i like programming veRy much';
$find = 'r';
$safeFind = preg_quote($find);
$wordStart = '<span class="whole_word">';
$wordEnd = '</span>';
$partStart = '<span class="sub_word">';
$partEnd = '</span>';

echo preg_replace_callback(
    "#\w*{$safeFind}\w*#iu",
    fn($m) => $wordStart . preg_replace("#{$safeFind}#iu", $partStart . '\0' . $partEnd, $m[0]) . $wordEnd,
    $str
);

Raw Output:

i like <span class="whole_word">p<span class="sub_word">r</span>og<span class="sub_word">r</span>amming</span> <span class="whole_word">ve<span class="sub_word">R</span>y</span> much

Rendered HTML

enter image description here

Upvotes: 0

Simon
Simon

Reputation: 23141

$str = "i like programming very much";
$word = "r";
function highlight($matches)
{
    global $word;
    return '<span class="pice1">'.str_replace($word,'<span class="pice2">'.$word.'</span>',$matches[0]).'</span>';
}
echo $str = preg_replace_callback("/([^\s]*?".preg_quote($word, '/')."[^\s]*)/siu", highlight, $str);

do the job(and it works with foreign languages too)...

Upvotes: 0

Toto
Toto

Reputation: 91385

What about this way :

$str = "i like programming very much";
$word = "r";
$list = explode(' ',$str);
for($i=0; $i<count($list); $i++) {
    if(preg_match("/$word/", $list[$i])) {
        $list[$i] = '<i>'.preg_replace("/$word/siu", "<b>$word</b>", $list[$i]).'</i>';
    }
}
$str = implode(' ',$list);
echo $str,"\n";

Upvotes: 1

Amarghosh
Amarghosh

Reputation: 59451

$str = "i like programming very much";
$w = "r";
echo preg_replace("/($w)/", "<b>$1</b>", $str);

Output:

i like p<b>r</b>og<b>r</b>amming ve<b>r</b>y much

Answer to the comment: do it in two steps.

$str = "i like programming very much ready tear";
$w = "r";
$str = preg_replace("/\\b((?:\\w+|\\b)$w(\\w+|\\b))\\b/", "<i>$1</i>", $str);
$str = preg_replace("/($w)/", "<b>$1</b>", $str);
echo $str;

output:

i like <i>p<b>r</b>og<b>r</b>amming</i> <i>ve<b>r</b>y</i> much <i><b>r</b>eady</i> <i>tea<b>r</b></i>

Upvotes: 2

Tokk
Tokk

Reputation: 4502

Why dont't you just use str_replace()? I think it's more simple

$search = "ab";
$word = "ameriabank";
$newstr = "<span class=\"pice1\">".str_replace($search, $word, "</span><span class=\"pice3\">".$search."</span></span class=\"pice1>\")."</span>";

Upvotes: 3

Related Questions