Dayo
Dayo

Reputation: 12805

Stymied by PHP preg_replace

Having a problem with the following preg_replace:

$subject = '<div class="main"> <div class="block_bc"> <a href="index.php?x_param=11" class="BC-1"> Gallery</a> / <a href="path/Title_Item/?x_param=17" class="BC-2"> Title Item</a> / <span class="BC-3"> Bridge</span> </div> </div>';
$regex = '/(<div\sclass=\"block_bc\"[^>]*>)([^<\/div>]*>)(<\/div>)/is';   
$replacement = '<div class="block_bc"></div>';
preg_replace($regex, $replacement, $subject);

Basically, I want to end up with <div class="main"> <div class="block_bc"></div> </div> but it is not getting selected.

Can anyone please point me to the "obvious" error?

Upvotes: 0

Views: 94

Answers (3)

complex857
complex857

Reputation: 20753

You try to use character classes ([]) wrong. The [^<\/div>]* part means that number of characters except one of the following: <,/,d,i,v,>. This probably not what you meant.

What you could use is non-greedy repeat:

$regex = '/(<div\s*class=\"block_bc\"[^>]*>)(.+?)(<\/div>)/is';

Also, getting things out from html with regexp can be extremely brittle, try using the DOM for this with xpath. It's more verbose but also more resilient for badly formatted input:

$subject = '<div class="main"> <div class="block_bc"> <a href="index.php?x_param=11" class="BC-1"> Gallery</a> / <a href="path/Title_Item/?x_param=17" class="BC-2"> Title Item</a> / <span class="BC-3"> Bridge</span> </div> </div>';

libxml_use_internal_errors(true); // supress warnings
$doc = new DOMDocument;
$doc->loadHTML($subject);

$xpath = new DOMXpath($doc);
// get the <div class="main"> node for exporting
$main_node  = $xpath->query('//div[@class="main"]');
// select the block_bc classed div's childs, and the textnodes under it
$childNodes = $xpath->query('//div[@class="block_bc"]/* | //div[@class="block_bc"]/text()'); 
foreach ($childNodes as $c) {
    $c->parentNode->removeChild($c); // clear them all
}

// export the part of the document under the <div class="main">
print $doc->saveHTML($main_node->item(0)); 
// update:
// if you want the full document in html you can simply omit the parameter, with this you can get rid of the $main_node = ... line too
print $doc->saveHTML(); // this will print from doctype to </html>

Upvotes: 1

cleong
cleong

Reputation: 7646

[^</div>] just creates a character class without '<', '/', 'd', 'i', 'v', and '>'. It is not doing what you think it would. Replacing the middle part with a non-greedy any match should do the trick:

'/(<div\sclass=\"block_bc\"[^>]*>)(.*?)(<\/div>)/is'

Upvotes: 0

urmaul
urmaul

Reputation: 7340

Pattern

~<div\sclass="block_bc"[^>]*>.*</div>~isU

will work until you add some divs inside "block_bc".

Upvotes: 0

Related Questions