1
$list = '<ul>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
</ul>';

How do I replace last <li>'s class from 'woman' to 'man'?

We should get finally:

$list = '<ul>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="man">photo</li>
</ul>';
James
  • 42,081
  • 53
  • 136
  • 161

4 Answers4

3

With a regular expression (which is greedy by default), it is quite easy:

$list = preg_replace ('#^(.*class=")woman(".*)$#s', '$1man$2', $list);

That won't take into account that the class might be on something other than an LI tag or if the last LI tag has no class. To fix the first, you can simply change the regex:

$list = preg_replace ('#^(.*<li class=")woman(".*)$#s', '$1man$2', $list);

To fix the last:

$list = preg_replace ('#^(.*)<li[^>]*>(.*)$#s', '$1<li class="man">$2', $list);
Steven Don
  • 2,436
  • 15
  • 14
2

Two options:

  1. Use regular expressions and formulate the regular expression according to your needs. E.g. replace the last li blocks class attribute with a different value.

    $list = preg_replace('#^(.*<li class=")(.*)(">.*</li>.*)$#s', '$1man$3', $list);

  2. Generate a DOM-Tree from the fragment and use xpath to adress the last li element. (DOM - documentation

fyr
  • 20,227
  • 7
  • 37
  • 53
  • I dont have an idea how to use all the info you gave me. Can you just give some peace of code, so I can accept your answer? – James Jun 26 '11 at 18:34
  • I added an example for the first option. The second option would be a little bit bloated for your usecase. If you happen to have more complex search/replace operations inside the html content it would be the appropriate way. – fyr Jun 26 '11 at 19:36
1

Try:

$off = strripos ( $list , "class=");
$list = substr_replace ( $list , "man" , $off+7, 5);

I think this is, by far, the simplest way to perform the trick, and no regexp needed at all!

danii
  • 5,553
  • 2
  • 21
  • 23
  • are you kidding? the is not a solution. – James Jun 26 '11 at 18:38
  • Sorry, I realized the other version was moronic, but I still think this is the best solution. Why get all complicated with regexps or DOM stuff when old plain string manipulation is all you need? – danii Jun 26 '11 at 19:11
1

Couldn't find a suitable duplicate, so here is the DOM solution:

$list = '<ul>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
<li class="woman">photo</li>
</ul>';

$dom = new DOMDocument;
$dom->preserveWhiteSpace = false;
$dom->loadXml($list);
$dom->documentElement->lastChild->setAttribute('class', 'man');
$dom->formatOutput = true;
echo $dom->saveXml($dom->documentElement);

http://codepad.org/6MVEytcp

If your markup is not XML compliant or if its a full html page consider using loadHTML to use libxml's HTML parser module. In that case, search around on StackOverflow or through my answers. There is plenty examples.

Gordon
  • 312,688
  • 75
  • 539
  • 559