使用PHP正则表达式将HTML元素移动到其父元素上方

I have HTML (generated by third party application) which I need to clean up and modify in various ways. One of the things I need to do is to move IMG elements that are nested inside P elements that contain other text and elements to their own paragraph. I'm aware of the PHP DOM extension and am using this for some things, but for this operation it would be preferable to use regular expressions. There may be zero or more P elements before the P containing the IMG element, the IMG element may have any elements or text before or after it inside the nesting P element, and there may be more than one IMG element nested in a single P. For example I'd like to transform

<p>Gah1</p><p>Blah1<img src="blah.jpg"/> Blah2</p><p>Gah2</p>

to

<p>Gah1</p><p><img src="blah.jpg"/></p><p>Blah1 Blah2</p><p>Gah2</p> 

I've tried:

preg_replace("/<p>(.*?)(<img\s+[^>]*\/>)(.*?)<\/p>/is", "<p>$2</p><p>$1$3</p>", $input);

but this puts the IMG element right at the beginning (because the reluctant first group still starts at the beginning of the string I guess):

<p><img src="blah.jpg"/></p><p>Gah1</p><p>Blah1 Blah2</p><p>Gah2</p>

And it would also only handle one image per paragraph. I've also tried various combinations of (negative) look-aheads but can't get these to work either. Help!

So instead of being stuck on trying to use a single regex to achieve this I ended up using multiple regexs and iteration:

// Check if there are any paragraphs containing images first.
if (preg_match('/<p[^>]*>.*?<img\s+[^>]*\/>.*?<\/p>/is', $input)) {
  // Get individual paragraphs.
  $paragraphs = array();
  preg_match_all('/<p[^>]*>.*?<\/p>/is', $input, $paragraphs);
  foreach ($paragraphs[0] as $para) {
    $images = array();
    if (preg_match_all('/<img\s+[^>]*\/>/is', $para, $images)) {
      // Strip images from this paragraph.
      $new_paras = preg_replace('/<img\s+[^>]*\/>/is', '', $para);

      // We put the images under the paragraph they were anchored in because they tend to 
      // be anchored in the paragraph they're visually positioned in or the one above.
      foreach ($images[0] as $img) {
        $new_paras .= "<p>$img</p>";
      }

      // Replace existing paragraph containing images.
      $input = str_replace($para, $new_paras, $input);
    }
  }
}

Along the way I tried using PHPs DOM extension, and found it to be horrendously cumbersome and difficult because previously obtained references to elements become messed up when other elements are modified or inserted (I'm still using it to sanitise and parse the original HTML though). I also found that using negative look-ahead or -behind in regexs to avoid matching multiple paragraphs would cause out-of-memory errors (the input string can be very long), hence breaking up the input into single paragraphs first in the code above.