Page 1 of 1

Replace nth occurence

Posted: Wed Sep 10, 2008 11:09 am
by anjanesh
Hi

I want to replace the 4th pattern only in a preg_replace.
This has nothing to with XML, so Im not looking for a DOM solution - just wanted to give a good example string

Code: Select all

<?php
$xml = "
<starttag>
    <starttag>content 1</endtag>
    <starttag>content 2</endtag>
    <starttag>content 3</endtag>
    <starttag>content 4</endtag>
    <starttag>content 5</endtag>
</endtag>
";
$pattern = '#((.*?<starttag>.*?</endtag>.*?){3})(<starttag>.*?</endtag>)#is';
$xml = preg_replace($pattern, '$1<starttag>content changed</endtag>', $xml, 1);
echo $xml;

Code: Select all

php preg_replace.php
 
<starttag>
    <starttag>content 1</endtag>
    <starttag>content 2</endtag>
    <starttag>content 3</endtag>
    <starttag>content changed</endtag>
    <starttag>content 5</endtag>
</endtag>
Is there a better solution ?

Thanks

Re: Replace nth occurence

Posted: Wed Sep 10, 2008 11:43 am
by prometheuzz
That's pretty much how to do it. You could cut down the runtime of your code by using some possessive quantifiers and instead of those .*? being a bit more specific in what to match. But in doing so, you'll make the regex more difficult to interpret and if your strings will be fairly small, you might not even notice the difference.

Anyway, here a (slightly) tuned version of what you already cooked up:

Code: Select all

(?s)((?:<starttag>[^<]++</endtag>(?:(?!<starttag>[^<]+</endtag>).)*+){3})<starttag>[^<]++</endtag>
HTH

Re: Replace nth occurence

Posted: Wed Sep 10, 2008 12:27 pm
by anjanesh
What does ?: do ?

Re: Replace nth occurence

Posted: Wed Sep 10, 2008 12:59 pm
by jayshields
(?:) non-capturing parentheses
I learnt that from http://www.cuneytyilmaz.com/prog/jrx/ :D

Re: Replace nth occurence

Posted: Wed Sep 10, 2008 4:59 pm
by prometheuzz
anjanesh wrote:What does ?: do ?
Yes, as mentioned, it's called a non-capturing parenthesis. When you do "(.*)" everything the .* matches will be remembered by the regex engine and can possibly be recalled upon by a back reference \1 or $1. Writing "(?:.*)" will tell the regex engine to "forget" the matched characters immediately: it will improve the run-time of the matching.