Попробуйте это:
preg_replace("/\w*?$keyword\w*/i", "<b>$0</b>", $str)
\w*?
соответствует любым символам слова перед ключевым словом (как можно меньше) и \w*
любым символам слова после ключевого слова.
И я рекомендую вам использовать preg_quote
для экранирования ключевого слова:
preg_replace("/\w*?".preg_quote($keyword)."\w*/i", "<b>$0</b>", $str)
Для поддержки Unicode используйте флаг u и \p{L}
вместо \w
:
preg_replace("/\p{L}*?".preg_quote($keyword)."\p{L}*/ui", "<b>$0</b>", $str)