Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Perl substitute with the nth match

by misterperl (Pilgrim)
on Jan 11, 2023 at 18:38 UTC ( [id://11149532]=perlquestion: print w/replies, xml ) Need Help??

misterperl has asked for the wisdom of the Perl Monks concerning the following question:

Apologies if this has been answered here or elsewhere; I did research, but it's one of those hard-to-describe questions for a SE..

Briefly I need to substitute the ordinal match sequence number for each match, like:

cat dog cat mouse eel cat housecat catamaran fish
I need a perlvar that has the nth match so I can write something like s/(cat)/^1/smg where ^1 would be the number of the nth "cat": matched. In that example I'd get:
1 dog 2 mouse eel 3 house4 5amaran fish
OF COURSE I can do this in a loop. Or with a /e.. I want a substitution with a Perlvar of the nth match, if one exists? TYVM!

Replies are listed 'Best First'.
Re: Perl substitute with the nth match
by choroba (Cardinal) on Jan 11, 2023 at 19:04 UTC
    > OF COURSE I can do this in a loop. Or with a /e

    Can you? I can, too:

    perl -pe 's/cat/++$i/ge' file

    There's no special variable that counts matches. But there's one that's incremented with each line of input: $.. So if we could tell Perl that cat instead of a newline is the line delimiter... but of course we can do that! That's what $/ is for.

    perl -pe 'BEGIN { $/ = "cat" } chomp; $_ .= $. unless eof' file

    Update: which can be rewritten to use substitution as you originally wanted:

    perl -pe 'BEGIN { $/ = "cat" } s{$/}{$.}' file

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      > > OF COURSE I can do this in a loop.

      > s/cat/++$i/ge

      interestingly it's possible to avoid /e in an efficient inside-out (TIMTOW) loop version of m///

      say pos($txt) while $txt =~ m/cat/g

      Now with s/// this kind of works, but isn't efficient because pos will be reset each time

      use v5.12; use warnings; use Data::Dump qw/pp dd/; my $txt = <<'___'; cat dog cat mouse eel cat housecat catamaran fish ___ say 'm-pos:', pos($txt) while $txt =~ m/cat/g; my $cnt=1; while ($txt =~ s(cat)($cnt)x) { say "s-pos:", pos($txt) // "undefined"; $cnt++; } say $txt;
      m-pos:3 m-pos:11 m-pos:25 m-pos:34 m-pos:38 s-pos:undefined s-pos:undefined s-pos:undefined s-pos:undefined s-pos:undefined 1 dog 2 mouse eel 3 house4 5amaran fish

      and no, using s///g would do the outer loop only once, tho there might be a way to force a single replace with (?FAIL) ... probably?

      Cheers Rolf
      (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
      Wikisyntax for the Monastery

Re: Perl substitute with the nth match
by haukex (Archbishop) on Jan 11, 2023 at 19:08 UTC
    I want a substitution with a Perlvar of the nth match, if one exists?

    If I understand your question correctly, then no, no such perlvar that keeps track of "how many" regexes have been executed/replaced exists, and you'll have to use one of the other methods you described. Update: Or the clever hack by choroba.

Re: Perl substitute with the nth match
by ikegami (Patriarch) on Jan 11, 2023 at 19:02 UTC

    Use /e to execute code to generate the substitution.

    s{ cat }{ ++$i }xeg
Re: Perl substitute with the nth match
by johngg (Canon) on Jan 11, 2023 at 22:21 UTC

    Perhaps a programmatic pattern?

    johngg@aleatico:~/perl/Monks$ perl -Mstrict -Mwarnings -E 'say q{}; my $text = <<__EOT__; cat dog cat mouse eel cat housecat catamaran fish __EOT__ my $n = 0; $text =~ s{cat(?{ $n++ })}{$n}g; say $text;' 1 dog 2 mouse eel 3 house4 5amaran fish

    I hope this is helpful.

    Cheers,

    JohnGG

      Just to add a note to this: while it may work in this case, in the general case, one should be careful with assuming how often a (?{...}) gets called, as is stated at the top of its documentation.

Re: Perl substitute with the nth match
by misterperl (Pilgrim) on Jan 11, 2023 at 20:01 UTC
    THank-you all very helpful replies. This is one of those rare times using the swiss-army-knife that is Perl was missing the exact blade I need!

      It isn't missing the blade. The blade is /e and you've just chosen not to use it for some undeclared reason.


      🦛

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11149532]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (6)
As of 2024-04-18 14:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found