Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Re (using assertions): pattern matching a limited number of times

by bart (Canon)
on Sep 14, 2002 at 09:13 UTC ( [id://197829]=note: print w/replies, xml ) Need Help??


in reply to pattern matching a limited number of times

I guess this would be a good place for assertions. An assertion is a piece of Perl code embedded in the regex, which says that a match may or may not succeed.

Now the current (perl5) syntax for a regex assertion is very awkward. This will do it:

/(?(?{NOTCOND})(?!))/
NOTCOND is perl code producing a true when you want the assertion to fail, because only in that case an attempt to match the regex snippet /(?!)/ is made, and this is a lookahead that never matches.

So, you can try this:

my $i = 0; s/ab(?(?{++$i>5})(?!))/cd/g;

This will indeed stop matching after the fifth match, producing the desired result; but it will not stop trying: it will go through the whole string, and if your string contains 50 substrings "ab", then the assertion code will be called 50 times. So for long strings, it won't be too efficient.

Replies are listed 'Best First'.
Re2: pattern matching a limited number of times
by blakem (Monsignor) on Sep 14, 2002 at 09:42 UTC
    How about a modified version of japhy's code.
    #!/usr/bin/perl -wT use strict; my $string = 'abc ' x 10; my $search = 'ab'; my $replace = 'CD'; print "$string\n"; my $i = 0; while ($string =~ /$search/gi) { substr($string, $-[0], $+[0]-$-[0], $replace); last if ++$i == 4; pos($string) = $-[0] + 1; } print "$string\n"; __END__ abc abc abc abc abc abc abc abc abc abc CDc CDc CDc CDc abc abc abc abc abc abc
    Update: Doh! I didn't see your very similar solution before I posted....

    -Blake

      Doh! I didn't see your very similar solution before I posted....
      It is very similar, isn't it? And I hadn't seen yaphy's solution before I posted mine. Now, it left me wondering: is setting pos() necessary, or will Perl DWIM, and continue matching at the same point in the (original) string without help? That's what s///g does.

      Well, it turns out that it appears to be using an offset in the string to keep track of where it was. So it is necessary.

      $_ = 'abxy' x 12; for(my $i = 0; m/ab/g and $i++<5;) { substr($_, $-[0], $+[0]-$-[0]) = 'abXab'; } print;
      Result: abXabXabXabXabXabxyabxyabxyabxyabxyabxyabxyabxyabxyabxyabxyabxy

      Not good.

      $_ = 'abxy' x 12; for(my $i = 0; m/ab/g and $i++<5;) { substr($_, $-[0], $+[0]-$-[0]) = 'abXab'; pos = $-[0]+5; } print;
      Result: abXabxyabXabxyabXabxyabXabxyabXabxyabxyabxyabxyabxyabxyabxyabxy

      Good.

      p.s. I noticed this, which is also very awkward:

      my $length = length(substr($_, 2, 2) = 'abXab'); print $length;
      prints 2, not 5. What happened to the rule: the value of an assignment as an expression, is what you assign?

        p.s. I noticed this, which is also very awkward:

        Aren't you simply being bitten by the same bug I reported here in thread which you commented on here?

        For reference, Perlbug assigned a ticket ID of [perl #16834].


        Well It's better than the Abottoire, but Yorkshire!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://197829]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2024-04-18 05:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found