Если вы все еще думаете об использовании регулярных выражений, проверьте это:
$source = <<<EOS
<img src="foo.png" title="A site about blue widgets" alt="blue-widget" />
<h2>This is a site about blue widgets</h2>
<p>We've got lots of blue widgets and blue widget accessories...';
EOS;
$term = 'blue widgets';
// convert search term to valid regex
$term0 = preg_replace(array('~\A\b~', '~\b\z~', '~\s+~'),
array('\b', '\b', '\s+'),
preg_quote(trim($term), '~'));
$regex = <<<EOR
~\A # anchoring at string start ensures only one match can occur
(?>
<(h[1-6])[^>]*>.*?</\\1> # a complete h<n> element
| </?\w+[^>]*+> # any other tag
| (?:(?!<|{$term0}).)*+ # anything else, but stop before '<' or the search term
)*+
\K # pretend the match really started here; only the next part gets replaced
{$term0}
~isx
EOR;
echo preg_replace($regex, "<strong>$0</strong>", $source);
запустите его на ideone.com
Я даже не был уверен, что возможно сделать это с помощью регулярного выражения, поэтому я решил разобраться с этим. Несмотря на то, что это решение отвратительно, оно настолько простое, насколько я мог. И чтобы сделать это, мне пришлось игнорировать многие факторы, которые могут его нарушить - например, разделы CDATA, комментарии SGML, элементы <script>
и угловые скобки в значениях атрибутов. И это только в допустим HTML.
Забавно, как это было, но я надеюсь, что это убедит вас раз и навсегда забыть о регулярных выражениях и использовать специальный инструмент, как советовали другие респонденты.