Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Adding regex filters from command-line options

by Anonymous Monk
on Mar 17, 2025 at 19:10 UTC ( [id://11164307]=perlquestion: print w/replies, xml ) Need Help??

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

I have a command-line download tool that extracts a list of filenames/urls upon which to operate. I added support to filter the list by accepting regex strings from --accept and --reject options. What I have works, but feels off because of the string eval. Is there another approach to this?
GetOptions( 'accept|a=s' => \my @accept, 'reject|r=s' => \my @reject, ) or die "Error with options\n"; my @filter = map eval "sub { \$_[0] =~ /$_/ }", @accept; push @filter, map eval "sub { \$_[0] !~ /$_/ }", @reject; # my @input = ([url, filename], ...); my @filtered = filter(@input); sub filter { return unless @filter; return map $_->[0], grep { my $f = $_; all { $_->($f->[1]) } @filter } @_; }

Replies are listed 'Best First'.
Re: Adding regex filters from command-line options
by ikegami (Patriarch) on Mar 17, 2025 at 19:12 UTC

    Use a closure which captures the pattern.

    my @filters = ( ( map { my $re = $_; sub { $_[0] =~ $re } } @accept ), ( map { my $re = $_; sub { $_[0] !~ $re } } @reject ), );

    You could even pre-compile the patterns.

    my @filters = ( ( map { my $re = qr/$_/; sub { $_[0] =~ $re } } @accept ), ( map { my $re = qr/$_/; sub { $_[0] !~ $re } } @reject ), );

    I suspect that building a single pattern would be faster, though.

    my $filter; if ( @accept || @reject ) { $filter = join "", ( map "(?=(?s:.*?)$_)", @accept ), ( map "(?!(?s:.*?)$_)", @reject ); $filter = qr/^$filter/; } else { $filter = qr/(*FAIL)/; } sub filter { map $_->[0], grep { $_->[1] =~ $filter } @_ }
      Nice! But note the first two solutions require an extra set of enclosing parenthesis or the @reject filters will silently not be applied.

        woops! Fixed.

Re: Adding regex filters from command-line options
by Anonymous Monk on Mar 25, 2025 at 08:29 UTC
    In "all { $_->($f->1) }" what is "all"? is it a Perl keyword?

      Is it most likely List::Util::all and the snippet given in the OP just does not include the use List::Util 'all'; line.


      🦛

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (3)
As of 2025-05-22 06:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.