views:

926

answers:

4

I have a Perl program that stores regular expressions in configuration files. They are in the form:

regex = ^/d+$

Elsewhere, the regex gets parsed from the file and stored in a variable - $regex. I then use the variable when checking the regex, e.g.

$lValid = ($valuetocheck =~ /$regex/);

I want to be able to include perl variables in the config file, e.g.

regex = ^\d+$stored_regex$

But I can't work out how to do it.

When regular expressions are parsed by Perl they get interpreted twice. First the variables are expanded, and then the the regular expression itself is parsed.

What I need is a three stage process: First interpolate $regex, then interpolate the variables it contains and then parse the resulting regular expression. Both the first two interpolations need to be "regular expression aware". e.g. they should know that the string contain $ as an anchor etc...

Any ideas?

+3  A: 

Using eval can help you here. Take a look at the following code it can precompile a regexp that's ready to be used latter:

my $compiled_regexp;
my $regexp = '^\d+$stored_regexp$';
my $stored_regexp = 'a';

eval "\$compiled_regexp = qr/$regexp/;";
print "$compiled_regexp\n";

The operator qr// can be used to precompile a regexp. It lets you build it but doesn't execute it yet. You can first build your regexps with it and then use them latter.

potyl
+3  A: 

Your Perl variables are not in scope within your configuration file, and I think that's a good thing. eval is scary.

You would be better off implementing your own templating.

So in the config file:

regex = ^\d+__TEMPLATE_FIELD__$

In the config file reader:

# something like this for every template field you need
$regex =~ s/__TEMPLATE_FIELD__/$stored_regex/g;

When using:

$lValid = ($valuetocheck =~ m/$regex/)

Move these around depending on at what point you want the template substitution to apply.

slim
+7  A: 

You can define the regexp in your configuration file like this:

regex = ^\d+(??{$stored_regex})$

But you will need to disable a security check in the block where you're using the regexp by doing this in your Perl program:

use re 'eval';
Leon Timmermans
It's elegant solution.
Hynek -Pichi- Vychodil
A: 

A tangentially related gotcha: If you do double interpolation inline, and you also have substitution strings in variables, consider:

# the concat with doublequotes in the replacement string 
#  are to make them PART OF THE STRING, NOT THE STRING DELIMITERS,
#  in other words, so the 2nd interpolation sees a double quoted string :
#     eval eval $replace -> eval $1 hello world -> syntax error 
#     eval eval $replace -> eval "$1 hellow world"  -> works ok 
# see: http://www.perlmonks.org?node_id=687031  

if($line =~ s/$search/'"' . $replace . '"'/ee) {
     # STUFF... 
}
sweaver2112