Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

RE: Selective substitution: not in Perl?

by atl (Pilgrim)
on Aug 16, 2000 at 14:25 UTC ( #28088=note: print w/replies, xml ) Need Help??


in reply to Selective substitution: not in Perl?

Hi,

a quick hack to solve your problem:

#!/usr/bin/perl -w use strict; my $string = "foo" x 4; print "$string\n"; my $pattern = "foo"; my $better = "bar"; my $n=1; $string =~ s/^(($pattern){$n})$pattern/$1$better/; print "$string\n";
$n holds the number of occurences to be skipped, so $n = 1 means the second will be replaced. The output:

atl@companion:~/perl/s > one.pl foofoofoofoo foobarfoofoo
I believe that's what you wanted. IMHO it ain't ugly, too. ;-)

Have fun ...

Andreas

Replies are listed 'Best First'.
RE: RE: Selective substitution: not in Perl?
by nuance (Hermit) on Aug 16, 2000 at 14:39 UTC
    That doesn't work, suppose I have the string "abacab" and want to replace the second a with an upper case A. Your regex doesn't match. How about this (untested):
    #!/usr/bin/perl -w use strict; my $string = "abacab"; print "$string\n"; my $pattern = "a"; my $better = "A"; my $n=1; my $i=0; $string =~ s/($pattern)/$i == $n ? $better : $1; i++/ge; print "$string\n"

    Nuance

      Black magic! I'm really impressed, I didn' know you can put that all into the substitution pattern. /me bows to Nuance ...

      As for my solution, I was focused on the sample input given, I didn't think of the more general problem. But you're right about this.

      As for your script, it works with a small alteration:

      $string =~ s/($pattern)/$i++ == $n ? $better : $1/ge;
      If you increment $i in a seperate statement, the whole block evaluates to the value of $i und you get
      abacab 0b1c2b
      Ok, now we're having fun :-)...

      Andreas (waiting for the chinese food delivery service ...)

        To make it even clearer, remember that the right side of the s///ge can be an arbitrary block. Here's the "Perl Bowling" style written for clarity:
        { my $count = 0; $string =~ s{($pattern)}{ my $source = $1; $count++; if ($count == $target) { $source = $replacement; # replace! } $source; # either original or replacement now }ge; };
        And yes, you can actually write it like that, just as you see. If you're doing anything odd in the right hand side in a s///e, I recommend expanding it out like that.

        -- Randal L. Schwartz, Perl hacker

      Thanks, your solution works great! I wrote a sub to convert sed-ish s///n constructs to your format, making conversion from sed easier:
      sub seval { my ($sub) = shift; $vni++; $sub =~ s#s/([^/]+)/([^/]+)/(.+)#s/\1/\$i$vni++ == \3 ? \2 : \$&/e +gs#; return $sub; } # Evals 's/foo/$i1++ == 1 ? bar : $&/egs' eval(seval("s/foo/bar/2"));
      Thanks again.
RE: RE: Selective substitution: not in Perl?
by davorg (Chancellor) on Aug 16, 2000 at 14:37 UTC

    I was going to give a similar solution, but then I realised that the previous (non-replaced) matches didn't necessarily have to be consecutive in the original string. Perhaps you you need to put optional separator space in the regex. Something like...

    $string =~ s/^(($pattern.*){$n})$pattern/$1$better/;
    --
    <http://www.dave.org.uk>

    European Perl Conference - Sept 22/24 2000, ICA, London
    <http://www.yapc.org/Europe/>
      The .* is greedy, as far as I can see that will always replace ithe last match if you have more than the number you need.
      my string = "foo_a_foo_b_foo_c_foo_d_foo_e_foo_f_foo" my $pattern = "foo" my $better = "bar" my $n = 1; $string =~ s/^(($pattern.*){$n})$pattern/$1$better/;
      would give:
      "foo_a_foo_b_foo_c_foo_d_foo_e_foo_f_bar"
      not
      "foo_a_bar_b_foo_c_foo_d_foo_e_foo_f_foo"

      Nuance

        You're absolutely right, of course. Now I remember why I didn't post that solution in the first place :(

        Update:

        On thinking about it further, I realise that:

        $string =~ s/^(($pattern.*?){$n})$pattern/$1$better/;

        will probably do the trick.

        --
        <http://www.dave.org.uk>

        European Perl Conference - Sept 22/24 2000, ICA, London
        <http://www.yapc.org/Europe/>

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (6)
As of 2022-05-25 13:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you prefer to work remotely?



    Results (90 votes). Check out past polls.

    Notices?