Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

can u suggest a regex for this ?

by misterperl (Pilgrim)
on Feb 03, 2023 at 14:34 UTC ( [id://11150123]=perlquestion: print w/replies, xml ) Need Help??

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

I often have requests to comment out BLOCKS of text, such as "comment out everything between and including each cat/^cat block. Example:
mouse cat 1 2 3 ^cat deer eel cat furbaby elk ^cat dog fish
the result I want is
mouse #cat #1 #2 #3 #^cat deer eel #cat #furbaby #elk #^cat dog fish
This can be in an array (one element per line) or a scalar. Usually I just loop thru the list and set a flag when hit cat, and unset it after leaving ^cat, and add the # if flagged. Which is like how I would do this in C. Every time I solve a problem in my brain in C, I always think to myself surely Perl has a better approach!.. Fugly code:
my $comment=0; for (@a) { $comment++ if /^cat\b/; $_ = '#'.$_ if $comment; $comment-- if /^\#\^cat\b/; }

Can you suggest a brief solution with a single no-looping regex, OR a map for an array? Or maybe a clever mapped split?

Much thanks and happy Day of the Earth-Rodent-Forecaster!

Replies are listed 'Best First'.
Re: can u suggest a regex for this ?
by jo37 (Deacon) on Feb 03, 2023 at 14:59 UTC

    If you want to do it with map:

    map {/^cat\b/ .. /^\^cat\b/ ? s/^/#/r : $_} @a;

    Greetings,
    -jo

    $gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$
      THAT is very ELEGANT and Perlish TYVM!

      I get an error with the "r" modifier but it seems to work without it? I'm on Perl 5.8.8 maybe /r isn't supported?

        Without /r, map would modify the original array, but this is not available in very old versions.

        Greetings,
        -jo

        $gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$
        I'm on Perl 5.8.8

        There have been recent discussions here about using old Perls. If it's not too impertinent to ask, would you mind divulging which O/S (and which version) you are running which has this Perl version installed? I'm unaware of any O/S still supported which has it. TYVM.


        🦛

      I just went back and ++'ed your reply JO , this is a game-changer. This construct has myriad applications in general.

      I'm always looking for ways to shorten code- its generally more maintainable, easier to read, and more reliable. This is a huge win to modify certain BLOCKS of text, in one statement.

      Like to change all "dog"s to "canine" only in XML pet blocks I might use: map {/^<pets>/ .. /^<\/pets>/ ? s/dog/canine/gir : $_ } @a;

      TY you made my month. I never knew how to do this ; I've tried all sorts of approaches over the years like regex assertions, etc.

      ++ to you for sure ; Id do ++^^10 if I could!

Re: can u suggest a regex for this ?
by hv (Prior) on Feb 03, 2023 at 15:26 UTC

    Your "fugly code" example suggests that you want to allow nesting of (cat ... ^cat) blocks, and that everything in the outer block should then get a single '#' inserted; and further, that if the final block is missing its closing "^cat" tag it should comment to the end of file. If both of those behaviours are required, then I'd probably prefer to stick with your example code - it makes it pretty clear what is going on, and could easily be extended to insert extra '#' characters for nested blocks if desired.

    jo37's solution is nice, but does not handle nested blocks: it will stop commenting as soon as it sees the first "^cat".

    If the "comment to end of file" behaviour is not desired, you may be better off with a recursive regexp that would only match balanced blocks.

Re: can u suggest a regex for this ?
by Discipulus (Canon) on Feb 03, 2023 at 15:49 UTC
    Hello misterperl

    also flip-flop can be used (look for the scalar context usage):

    use strict; use warnings; while (<DATA>){ print /^cat/ .. /^\^cat/ ? "#$_" : $_; } __DATA__ mouse cat 1 2 3 ^cat deer eel cat furbaby elk ^cat dog fish

    L*

    PS ^\^ is actually a cat :)

    PPS overlooked previous answer was already using flip-flop.. let rephrase: you can also use flip-flop directly :)

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: can u suggest a regex for this ?
by tybalt89 (Monsignor) on Feb 03, 2023 at 17:32 UTC

    Scalar without /r

    #!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11150123 use warnings; my $blockoftext = <<END; mouse cat 1 2 3 ^cat deer eel cat furbaby elk ^cat dog fish END $blockoftext =~ s/^cat.*?^\^cat/ my $catsection = $&; $catsection =~ s!^!#!gm; $catsection /gems; print $blockoftext;

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (6)
As of 2024-04-18 06:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found