RenishV8
RenishV8

Reputation: 186

Regex php, replace ul li by div

I have this list:

<ul>
    <li class="myclass">blablabla 1</li>
    <li class="myclass">blablabla 2</li>
    <li class="myclass">blablabla 3</li>
</ul>

And I want, with a regex, this:

<div class="newClass">blablabla 1</div>
<div class="newClass">blablabla 2</div>
<div class="newClass">blablabla 3</div>

Replacing only <li> works, with this regex:

$pattern = '#<li class="newClass">(.+)</li>#';
$replacement = '<div class="newClass">$1</div>';
$texte = preg_replace($pattern, $replacement, $texte);

I tried to replace the <ul> too, but it doesn't work:

$pattern = '#<ul>(<li class="myclass">(.+)</li>)*</ul>#';
$replacement = '<div class="newClass">$2</div>';
$texte = preg_replace($pattern, $replacement, $texte);

What is wrong?

Upvotes: 3

Views: 2986

Answers (2)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626923

You can perform all the <li> replacements outside of <ol>...</ol> tags with the following regex:

(?(DEFINE)(?<skip><ol>.*?<\/ol>))(?&skip)(*SKIP)(*FAIL)|\s*<li\s+class="myclass">(.*?)<\/li>\s*

(?(DEFINE)                  # We set up conditions
   (?<skip><ol>.*?<\/ol>))  # What we skip
   (?&skip)(*SKIP)(*FAIL)   # Fail what we skip
|                           # Else, match this
\s*<li\s+class="myclass">(.*?)<\/li>\s*

And replacement string will be:

<div class="newClass">$3</div>\n

Then, you will just have to remove <ul> and </ul> tags.

See the main regex demo here, and the sample program here.

<?php
   $str = "<ul>\n    <li class=\"myclass\">blablabla 1</li>\n    <li class=\"myclass\">blablabla 2</li>\n    <li class=\"myclass\">blablabla 3</li>\n</ul>\n<ol>\n    <li class=\"myclass\">blablabla 1</li>\n    <li class=\"myclass\">blablabla 2</li>\n    <li class=\"myclass\">blablabla 3</li>\n</ol>\n<ul>\n    <li class=\"myclass\">blablabla 1</li>\n    <li class=\"myclass\">blablabla 2</li>\n    <li class=\"myclass\">blablabla 3</li>\n</ul>"; 
   $re = "/(?(DEFINE)(?<skip><ol>.*?<\\/ol>))(?&skip)(*SKIP)(*FAIL)|\\s*<li\\s+class=\"myclass\">(.*?)<\\/li>\\s*/s"; 
   $subst = "<div class=\"newClass\">$3</div>\n";
   $result = preg_replace($re, $subst, $str);
   echo preg_replace("/<\/?ul>/", "", $result);
?>

Output:

<div class="newClass">blablabla 1</div>                                                                                                                                                                                                                
<div class="newClass">blablabla 2</div>                                                                                                                                                                                                                
<div class="newClass">blablabla 3</div>                                                                                                                                                                                                                

<ol>                                                                                                                                                                                                                                                   
    <li class="myclass">blablabla 1</li>                                                                                                                                                                                                               
    <li class="myclass">blablabla 2</li>                                                                                                                                                                                                               
    <li class="myclass">blablabla 3</li>                                                                                                                                                                                                               
</ol>                                                                                                                                                                                                                                                  
<div class="newClass">blablabla 1</div>                                                                                                                                                                                                                
<div class="newClass">blablabla 2</div>                                                                                                                                                                                                                
<div class="newClass">blablabla 3</div>

Upvotes: 0

karthik manchala
karthik manchala

Reputation: 13640

Your pattern is almost correct.

$pattern = '#<ul>(<li class="myclass">(.+)</li>)*</ul>#';

Although, there are multiple flaws in your pattern.

  • <ul> will assume that all your <li ... will start with <ul> which is not the case for <li class="myclass">blablabla 2</li>. So, you have to use it with ? and preferrably in a non capturing group.. i.e. (?:<ul>)? and similarly at the end (?:<\/ul>)? (note the escape character)

  • You are not checking for spaces and newlines before/after <li.. which should be changed to (\s*<li class="myclass">(.+)<\/li>\s*)

  • Also, no need to add * after (<li ...>...<\/li>)

Working modification of your pattern would be (?:<(?:ul|ol)>)?(\s*<li class="myclass">(.+)<\/li>\s*)(?:<\/(?:ul|ol)>)?

See demo for more explanation and exploration.

Upvotes: 2

Related Questions