olivierg
olivierg

Reputation: 792

generate 'next ifs' from config file in Perl

there is something in Perl I don't know how to code, can I request your help please.

basically, I'm trying to use a configuration file with an array (or a hash or anything of that sort) containing "exceptions" that I want to use in a "next if" of a loop of the main program.

exemple :

my program looks like that :

while(<>) {
    next if /regex1/;
    next if /regex2/;
    next if /regexN/;
}

and I want to be able to put these "next if" from a config file, like :

my %conf = do './config_file.conf';
while(<>) {
    # put code here to add all 'next ifs';
}

config file example :

exceptions   =>   [
                    'regex1',
                    'regex2',
                    'regexN',
                  ],

how can I do this easily in my code ? (where the comment is, that is, adding all "next if" from an array

thanks ! regards,

Upvotes: 1

Views: 90

Answers (4)

Sobrique
Sobrique

Reputation: 53498

In addition to the existing answers - I'd probably expand it to compile up a regex from my input:

#!/usr/bin/env perl
use strict;
use warnings;

my %conf = ( exceptions => [ 'regex1', 'regex2', 'regexN', ], );

my $match = join ( "|", @{$conf{exceptions}} ); 
   $match = qr/\b$match\b/;

print "Using regex of: ",$match,"\n";

while ( <DATA> ) {
   next if /$match/;
   print;
}

__DATA__
regex0
regex1
regex2
regexA
regexB
regexN

This has an advantage over grep in particular, that grep will iterate the whole list of regex, even if it hits a match early on. That won't matter noticeably if you've a small number of patterns though.

For bonus points, you may want to sort by likelihood of 'hit', so a match is located earlier on. By default, sorting by length might do it.

(And note - I use \b word boundary anchors, which may not be what you want to do, given you are using regex as input)

Upvotes: 1

simbabque
simbabque

Reputation: 54373

This is very inefficient! Don't do this. You should pre-compile the pattern instead.

You can use a another loop to iterate over all your patterns inside of your while. If you assign a label to your while loop you can next that directly.

my %conf = ( exceptions => [ 'regex1', 'regex2', 'regexN', ], );

OUTER: while (<DATA>) {
    foreach my $re (@{ $conf{exceptions} }) {
        next OUTER if m/$re/;
    }
    print;
}

__DATA__
regex0
regex1
regex2
regexA
regexB
regexN

This will output

regex0
regexA
regexB

Note that the do './config_file.conf' is very safe. You should use a module to read a config file format instead. That will make your code more portable and make sure no code you might not control gets executed. For example, you could use JSON, or Config::Simple.

Upvotes: -1

ikegami
ikegami

Reputation: 386331

Don't compile the patterns over and over again as simbabque and olivierg have recommended!

my %conf = ( exceptions => [ 'regex1', 'regex2', 'regexN', ], );

my $exceptions_re = join '|', @{ $conf{exceptions} };
$exceptions_re = qr/$exceptions_re/;

while (<DATA>) {
   next if /$re/;
   print;
}

If what you claim are regex patterns are actually strings to match literally, change

my $exceptions_re = join '|', @{ $conf{exceptions} };

to

my $exceptions_re = join '|', map quotemeta, @{ $conf{exceptions} };

Upvotes: 4

olivierg
olivierg

Reputation: 792

mmh it seems working with :

next if grep /$_/, @{$conf{exceptions}};

don't know if it's really clean tho

any other idea ?

Upvotes: 0

Related Questions