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

Question 1. How can I apply modifiers to a substitution via a variable, as in the following code?
#!/usr/bin/perl my $string = "aaaaaaaaa"; $modifiers = "g"; $string =~ s/a/b/$modifiers; print $string;
Question 2. Similarly, how can I ensure that variables within the substitution are interpreted as regular expressions... for example:
#!/usr/bin/perl my $string = "aaaaabbbbaaaaaa"; $replace = "$1"; $string =~ s/a+(b+)a+/$replace/g; print $string;
This results in $1 rather than bbbb which I want.

Replies are listed 'Best First'.
Re: How to apply modifiers to a substitution via variable?
by GrandFather (Saint) on Jan 31, 2007 at 22:26 UTC
    use strict; use warnings; my $string = "aaaaaaaaa"; my $modifiers = "g"; eval "\$string =~ s/a/b/$modifiers;"; print $string;

    Update: note that only question 1 was answered because only question 1 was asked at the time of posting. OP performed a substantive silent update subsequent to the initial create.


    DWIM is Perl's answer to Gödel
Re: How to apply modifiers to a substitution via variable?
by ikegami (Patriarch) on Jan 31, 2007 at 23:50 UTC

    I find the suggestions to use eval EXPR unwise and suggestions to use s///ee (eval EXPR's disguised form) deplorable. Don't generate code for eval that you can't easily validate. Fortunately, eval EXPR is not needed. Here's a copy of my earlier answer to the same question.

    For imsx, you can use (?switches:pattern). For g, you'll have to use an if.

    my $source = "abc"; my $find = "a"; my $replace = "x"; my %opts = ( i => 1, m => 0, s => 0, x => 0, g => 1, ); my $opts = join '', map { $opts{$_}?$_:'' } qw( i m s x ); my $re = "(?$opts:$find)"; if ($opts{g}) { $source =~ s/$re/$replace/g; } else { $source =~ s/$re/$replace/; } print $source;

    Update: Fixed where %opts was referenced as %opt.

      Except that, since you didn't use strict or warnings, which IMO is just as "deplorable" as using eval, you've got a hidden error:
      use strict; use warnings; my $source = "abc"; my $find = "a"; my $replace = "x"; my %opts = ( i => 1, m => 0, s => 0, x => 0, g => 1, ); my $opts = join '', map { $opt{$_}?$_:'' } qw( i m s x ); my $re = "(?$opts:$find)"; if ($opt{g}) { $source =~ s/$re/$replace/g; } else { $source =~ s/$re/$replace/; } print $source;

      s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/

      Here's the output from ikegami's code above, (but with strict and warnings applied):

      Global symbol "%opt" requires explicit package name at test.pl line 16 +. Global symbol "%opt" requires explicit package name at test.pl line 19 +. Execution of test.pl aborted due to compilation errors

      Update:  To clarify a bit ... I don't really think that skipping use strict; and use warnings; is "deplorable".  But I also don't think that sometimes using eval or the /e modifier to a regular expression is, either. ;-)


      s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/

        I didn't say it was tested code. And it's just a snippet to be inserted into a larger program with use strict and use warnings.

        And I didn't say /e (which is harmless), but /ee. If you're going to execute untrusted code, at least make it obvious. Don't hide it!

Re: How to apply modifiers to a substitution via variable?
by jettero (Monsignor) on Jan 31, 2007 at 22:30 UTC

    Something like my $reg = qr{(?$modifiers:$regular)} would probably work...

    my $string = "aaaaaaaaa"; $modifiers = "g"; $string =~ s/(?$modifiers:a)/b/; # ?? print $string;

    Although, the more I think about it... I don't think /g in there. /i does.

    For that second question, though, I think you'll have to eval like the post above.

    -Paul

Re: How to apply modifiers to a substitution via variable?
by liverpole (Monsignor) on Jan 31, 2007 at 22:38 UTC
    Hi lokiloki,

    Grandfather's answered your first question already.

    In answer to your second, you can use eval for this as well, but make sure you put apostrophes (') around the $1 in the assignment, rather than quotes ("), or you'll get an error.  Here's the code:

    #!/usr/bin/perl use strict; use warnings; my $string = "aaaaabbbbaaaaaa"; my $replace = '$1'; eval "\$string =~ s/a+(b+)a+/$replace/g"; print $string;

    bbbb

    Note that you need to use quotes (") around the eval statement so that $1 will interpolate, but (as Grandfather did) you still have to escape $string with the backslash "\" in the same line (\$string), so it won't interpolate.


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
Re: How to apply modifiers to a substitution via variable?
by GrandFather (Saint) on Jan 31, 2007 at 22:51 UTC

    For the second issue generally /e (evaluate) is used, but you need it twice. Remember to quote the $ in the string for $replace, or use single quotes so Perl doesn't try to interpolate $1:

    my $replace = '$1'; $string =~ s/a+(b+)a+/$replace/eeg;

    DWIM is Perl's answer to Gödel
Re: How to apply modifiers to a substitution via variable?
by johngg (Canon) on Jan 31, 2007 at 22:53 UTC
    You can do the second part without an eval but with an ee modifier, like this

    $ perl -le ' > $str = q{aaabbbaaa}; > $repl = q{$1}; > $str =~ s{a+(b+)a+}{$repl}ee; > print $str;' bbb $

    The first e executes the $repl resulting in $1, the second e executes the $1 resulting in whatever was captured, "bbb" here.

    Cheers,

    JohnGG