 <p>Edit: I updated the code to work better.</p> <p>I'm unsure exactly what the issue is but looking at your code I wouldn't be surprised that the negative look behind regex isn't matching multiple word strings where the "keyword" is not the first word after the src or alt. It might possible to beef up the regex, but IMHO a complicated regex might be a little too brittle for your html parsing needs. I'd recommend doing some basic html parsing yourself and doing a simple string replace in the right places.</p> <p>Here's some basic code. There is certainly a much better solution than this, but I'm not going to spend too much time on this. Probably, rather than inserting html in a text node, you should create a new html <code>a</code> element with the right attributes. Then you wouldn't have to decode it. But this would be my basic approach.</p> <p> <pre><code>$text = "Lorem ipsum &lt;img src=\"lorem ipsum\" alt=\"dolor sit amet\" /&gt; dolor sit amet"; $result = array( array('keyword' =&gt; 'lorem', 'link' =&gt; 'http://www.google.com'), array('keyword' =&gt; 'ipsum', 'link' =&gt; 'http://www.bing.com'), array('keyword' =&gt; 'dolor sit', 'link' =&gt; 'http://www.yahoo.com'), ); $doc = new DOMDocument(); $doc-&gt;loadHTML($text); $xpath = new DOMXPath($doc); foreach($result as $row) { if (!empty($row['keyword'])) { $search = $row['keyword']; $replace = '&lt;a href="'.$row['link'].'.html" class="ared"&gt;'.$row['keyword'].'&lt;/a&gt;'; $text_nodes = $xpath-&gt;evaluate('//text()'); foreach($text_nodes as $text_node) { $text_node-&gt;nodeValue = str_ireplace($search, $replace, $text_node-&gt;nodeValue); } } } echo html_entity_decode($doc-&gt;saveHTML()); </code></pre> <p>The <code>$result</code> data structure is meant to be similar to result of your <code>mysql_fetch_array()</code>. I'm only getting the children of the root for the created html DOMDocument. If the <code>$text</code> is more complicated, it should be pretty easy to traverse more thoroughly through the document. I hope this helps you.</p>