Reputation: 186
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
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
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