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

I'm trying to read regular expressions from a parameter file. This works as long as I specify the outer delimiters around the variable in the code. I include the delimiters in the variable, otherwise I have no way of allowing users to generate expressions that use external modifiers like:
/coWs/i
The parameter file (following) uses the first character to specify what operation (search or exception) the user wants to perform. The regexp runs from column 2 to the end of the line. What I want to do is use delimiters and modifiers included in the parameter file:
+/six/i -/were/
This works when delimiters are not included in the parameter file, but is very limited and flakey.
+[Ss][Ii][Xx]
Here is some of the code:
# Process Global Exceptions first foreach $except (@$glob_except) { $cexcept = substr($except, 1); $targf{$tkey} = "1:0" if ($tkey =~ /$cexcept/); # EXPANDS VARIABL +E HERE ### I would like the delimeters to be contained in the variable: ...( +$tkey =~ $cexcept); } elsif ($ttype eq '+') { if ($tkey =~ /$ttext/) { ; # EXPANDS VARIABLE HERE $targf{$tkey} = "3:$err_rtn"; $found = 1; } } elsif ($ttype eq '-' && substr($targf{$tkey},0,1) == 3) { if ($tkey =~ /$ttext/) {; # EXPANDS VARIABLE HERE $targf{$tkey} = "2:0"; $found = 0; } } else { ### ETCETERA ### THIS IS HOW THE HASH CONTAINING THE MATCH STRING IS LOADED elsif ($line_header eq '!') { ## Optional # Spec a global exception that affects all lines # interpolation takes place. unless ($trans_state == 2) {die "ERR: Global exception out of sequence";} push (@$glob_except, $line); # <= LOADING THE VARIABLE FROM + FILE # Trans state stays at 2 until set to 3 in subsequent logic

Replies are listed 'Best First'.
Re: How do pack a regular expression in a variable?
by japhy (Canon) on Nov 29, 2001 at 21:45 UTC
    You want to use eval(), I'd say. This is almost exactly a section of my book that I wrote last night!
    open REs, "< re_file" or die "can't read re_file: $!"; while (<REs>) { chomp; my $mode = substr($_, 0, 1, ''); # reverse-chop push @re, [ $mode, match_maker($_) ]; } close REs; # make me a match... ;) sub match_maker { my $pat = shift; return eval qq{ sub { \$_[0] =~ $pat } }; }
    If you call match_maker($foo), and $foo is '/age:\s*(\d+)/i', then the resulting function returned behaves exactly like:
    sub { $_[0] =~ /age:\s*(\d+)/i }
    Now you have an array, @re, with array references holding the mode ('+' or '-') and a function you can run to match against a string.
    for (@re) { my ($mode, $func) = @$_; if ($func->($string)) { # this is your pattern match! if ($mode eq '+') { print "this is ok\n"; } else { print "this matched an exception\n"; } } }

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker.
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: How do pack a regular expression in a variable?
by davorg (Chancellor) on Nov 29, 2001 at 22:37 UTC

    Perhaps you need to include your options within the regular expression. For example:

    /(?i)foo/

    is equivalent to

    /foo/i

    You can then leave the delimiters off and just put (?i)foo in your configuration file.

    See "Cloistered Pattern Modifiers" on p186 of the Camel (3ed) or the perlre section on (?imsx-imsx) for more details.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you don't talk about Perl club."

Answer: How do pack a regular expression in a variable?
by Anonymous Monk on Nov 30, 2001 at 20:14 UTC
    I came up with something that seems to work - using an eval to evaluate a string containing the regular expression variable...
    FEOUTER: while ($tkey = each(%targf)) { # Apply Search and Exception to each log line $found = 0; foreach $scline (@$srch_except) { # Split string intonext FEOUTER; qualifier and text $ttype = substr($scline, 0, 1); $ttext = substr($scline, 1); $eval_cd = "\"$tkey\" =~ $ttext"; if ($ttype eq '!') { if (eval "$eval_cd") { $targf{$tkey} = "1:0"; next FEOUTER; } } elsif ($ttype eq '&') {