in reply to Can I get some help with a regex please

The only reason I can imagine for using substitution in a situation like this is if the block of text to be changed is a sub-block within a larger text block:

c:\@Work\Perl\monks>perl -wMstrict -le "my $str = qq{cat\nman\ncat\ndog\neel\nman\nman\ncat\ncat\nman\n}; ;; my $sub_str = qq{cat\nman\n}; my $n = 3; ;; $str =~ s{ (\Q$sub_str\E) }{ join '', map qq{$_ $1}, 1 .. $n }xmsge; print qq{>$str<}; " >1 cat man 2 cat man 3 cat man cat dog eel man man cat 1 cat man 2 cat man 3 cat man <
(The \Q...\E metaquoting (update: of the interpolated $sub_str string) is necessary so that newlines are matched literally when the /x modifier is used.)

Of course, once you have this structure, it's easy to go to full regex search/replace:

c:\@Work\Perl\monks>perl -wMstrict -le "my $str = qq{cat\nman\ncat\ndog\neel\nman\nman\ncat\ncat\nwoman\n}; ;; my $sub_str = qr{ cat \n (?: wo)? man \n }xms; my $n = 3; ;; $str =~ s{ ($sub_str) }{ join '', map qq{$_ $1}, 1 .. $n }xmsge; print qq{>$str<}; " >1 cat man 2 cat man 3 cat man cat dog eel man man cat 1 cat woman 2 cat woman 3 cat woman <
(Update: Note that metaquoting is not needed here because $sub_str is a Regexp object: \n matches a literal newline.)


Give a man a fish:  <%-{-{-{-<

Replies are listed 'Best First'.
Re^2: Can I get some help with a regex please
by misterperl (Friar) on Jun 14, 2023 at 14:16 UTC
    The question isn't so much about the "reason" I need to do this- more like a better WAY to do it.

    After 30 years of programming Perl, and hours with Larry Wall and Damian and other gurus, my mindset is always CAN I DO THIS BETTER IN A REGEX?

    Reluctantly , I sometimes have to capitulate and conclude NO, there is no "better regex approach". This MIGHT be that. The tite loop I showed was the shortest and clearest solution so far.

    The real question is,

    are there RHS "tricks" I can do with $1 $2 ... ? like a way to repeat $1 $n times? And a way to know what iteration each is?
    It would seem "perlish" to have this capacity. Like:
    s/(block)/$1{$n}/
    where $1 is repeated $n times.. Im not sure about a way to know which iteration its on- maybe a reserved PerlVar?

      In any sort of production code, i would go so far as to recommend a clearer if slower classic C-style for loop. Yes, it's not optimized, but it is maintainable by someone who isn't a perl expert:

      my $result = ''; for(my $i = 0; $i < $n; $i++) { $result .= "$i cat\n\man\n"; }

      Or a slightly different variant that would lead itself to easier debugging:

      my @lines; for(my $i = 0; $i < $n; $i++) { push @lines, "$i cat"; push @lines, "man"; } #print Dumper(\@lines); my $result = join("\n", @lines);

      Unless it's really timing critical code (in which case thinking about doing the stuff in XS/Inline::C is also an option), long term maintainability and readability is (almost) always more important than saving a couple percent CPU cycles.

      So the answer, at least from my point of view: Can you do it faster with a regular expression: Maybe. Can you do it better? Not a chance, unless you add a few long paragraphs of explanations in the code comments that clearly lays out how to chance/update the code in a few years to fit the changing requirements of the project.

      PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP