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

I am writing a program that requires being able to load in a list of strings representing regexes and regex options from a ascii file and then construct a list of compiled regexes from them. The code looks something like this:
use strict; sub make_regex_list{ my @regexes; foreach my $strings (@_) { my($regex_string,$options)=@$strings; push @regexes,qr/(?$options)$regex_string/; } return @regexes; } my $string = "Jack Jack John"; # in real code this array would be constructed # from a file my @reStrings=(["jack","ig"],["john","i"]); my @REGEXES=make_regex_list(@reStrings); foreach my $regex (@REGEXES) { $string=~s/$regex/name/; } print $string."\n";
It doesn't quite work how I want it to though. The output appears like this,
"name Jack name"
So, it appears the 'i' option works, but not the 'g'. What can I do to get the 'g' option to work? I know I can use eval , but I would like to avoid this. Thanks!

Replies are listed 'Best First'.
Re: Constructing a list of regexes
by Enlil (Parson) on Feb 20, 2003 at 21:05 UTC
    IIRC there is no g mode modifier only ixsm mode modifiers (granted there is a /g option for the regular expression, but that is different). Anyhow here is one solution (semi-tested):
    use strict; sub make_regex_list{ my @regexes; foreach my $strings (@_) { my($regex_string,$options)=@$strings; push @regexes,qr/(?$options)$regex_string/; } return @regexes; } my $string = "Jack Jack John JACK john"; # in real code this array would be constructed # from a file my @reStrings=(["jack","ig"],["john","i"]); my @REGEXES=make_regex_list(@reStrings); foreach my $regex (@REGEXES) { #check to see if the regex contains the g modifier in it; if ( $regex =~ /^\(\?-xism:\(\?[^g|\)]g.*?\)/ ) { $string=~s/$regex/name/g; } else #no g modifier in $regex { $string=~s/$regex/name/; } } print $string."\n"; __END__ E:\>237215.pl name name name name john

    -enlil

Re: Constructing a list of regexes
by webengr (Pilgrim) on Feb 20, 2003 at 21:29 UTC

    As Enlil already pointed out, the problem is that the s/// and qr// operators don't take the same options. A quick consultation with the Camel book reveals that the qr// operator only accepts modifiers from the set "ismxo".

    Another approach you could consider is to use a hash instead of a list, with the keys being the regex as you already use, and the value being true or false (1 or 0) depending on whether you want global matching or not. Not elegant, but it works.


    use strict; sub make_regex_list{ my %regexes; foreach my $strings (@_) { my($regex_string,$options)=@$strings; if ($options =~ /g/) { $regexes{qr/(?$options)$regex_string/} = 1; } else { $regexes{qr/(?$options)$regex_string/} = 0; } } return %regexes; } my $string = "Jack Jack John"; # in real code this array would be constructed # from a file my @reStrings = (["jack","ig"],["john","i"]); my %regexes = make_regex_list(@reStrings); foreach my $regex (keys %regexes) { if ($regexes{$regex}) { print "Using $regex in global mode\n"; $string =~ s/$regex/name/g; print $string."\n"; } else { print "Using $regex\n"; $string =~ s/$regex/name/; print $string."\n"; } }

    Results in,

    Using (?-xism:(?i)john) Jack Jack name Using (?-xism:(?ig)jack) in global mode name name name


    PCS
Re: Constructing a list of regexes
by fletcher_the_dog (Friar) on Feb 20, 2003 at 22:16 UTC
    I thought of another question while reading these responses. If I want to read in the substitution value from a file and the substitution contains backreferences, how can I make that work? For example:
    my $new_value='$2 and $1'; my $string="(Jack) and (John)"; my $regex=qr/$string/; $string=~s/$regex/$new_value/;
    This obviously won't work how I intend, but how would I do this?
      The following will work. There was another problem with your example. "(Jack) and (John)" the literal string, does not match itself as a pattern with capturing parentheses.
      my $new_value='$2 and $1'; my $string="(Jack) and (John)"; my $regex=qr/$string/; $string = "Jack and John"; eval "\$string=~s/\$regex/$new_value/"; print $@ if $@; print "$string\n";