Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

use of constants in regex substitutions?

by Anonymous Monk
on Sep 22, 2003 at 23:23 UTC ( #293323=perlquestion: print w/replies, xml ) Need Help??

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

Given the code below:
#!/usr/bin/perl use strict; use constant { MIF_EXTENSION => "\.mif", TXT_EXTENSION => "\.txt" }; my $s0 = 'abcd.txt'; print "s0 =\t$s0\n"; $s0 =~ s/\.txt/\.mif/; print "s0 =\t$s0\n"; my $s1 = 'efgh.txt'; print "s1 =\t$s1\n"; $s1 =~ s/TXT_EXTENSION/MIF_EXTENSION/; print "s1 =\t$s1\n";

Scalar $s0 is substituted correctly, yet $s1 is not. What is required to get constants within substitutions to behave as desired? I was unsuccessful with specifying \Q...

Thanks.

Replies are listed 'Best First'.
Re: use of constants in regex substitutions?
by Zaxo (Archbishop) on Sep 22, 2003 at 23:38 UTC

    Hidden underneath, constants are subs. That means they are not evaluated in quoted context without some intervention. The "@{[]}" and "${\}" tricks are good for that. That applies to the left(regex) argument of s///.

    To get the constant to evaluate on the right (string) side, you need to use the /e flag. $s1 =~ s/${\TXT_EXTENSION}/MIF_EXTENSION/e;

    After Compline,
    Zaxo

Re: use of constants in regex substitutions?
by dmitri (Priest) on Sep 22, 2003 at 23:33 UTC
    You can treat constants as subroutines (which they are). In your case, the statement should look something like this:
    $s1 =~ s/&TXT_EXTENSION/&MIF_EXTENSION/e;
    Note the 'e' quantifier after the regex -- this tells the engine to evaluate the substitute before the substitution.

    Update: this code is incorrect, thanks to 3dan for pointing this out.

      That won't work, because the /e modifier only applies to the second part of the substitution (i.e. the 'substitute with...' part). The first part of the regex follows normal string-interpolation rules, and "&sub" is NOT interpolated in a string any more than "sub" is. This regexp looks for the literal text '&TXT_EXTENSION', and substitutes it with '.mif'.

      See Zazo's reply for a correct answer.

      --
      3dan

        You're right; I should've tested first. How come &sub is interpolated when using arrow operator?
        &sub => "xyz";
        AFAIK, this is equivalent to
        "&sub", "xyz";
Re: use of constants in regex substitutions?
by perlmonkey (Hermit) on Sep 23, 2003 at 01:38 UTC
    This is probably overkill, but you can create a tied object wrapper to do the look ups. This will be a bit slow, but if you dont need speed, it might be interesting to look at.
    use strict; my $str = "foobar"; my $c = MyConstants->new(); print "str = $str\n"; $str =~ s/$c->{Foo}/$c->{Bar}/; print "str = $str\n"; print "Bar = $c->{bar}"; package MyConstants; use constant Foo => "foo"; use constant Bar => "bar"; use Tie::Hash; use base qw(Tie::StdHash); use Carp qw(croak); sub new { tie my %self, $_[0]; return bless \%self, $_[0]; } sub FETCH { if( $_[0]->can($_[1]) ) { goto &{$_[1]}; } else { croak("Undefined constant \"$_[1]\" called"); } }
    results:
    str = foobar str = barbar Undefined constant "bar" called at /tmp/test.pl line 8
Re: use of constants in regex substitutions?
by edan (Curate) on Sep 23, 2003 at 11:27 UTC

    use constant {
        MIF_EXTENSION => "\.mif",
        TXT_EXTENSION => "\.txt"
    };

    This is not doing what you want it to. The backslash is interpreted when perl parses the double-quoted string, so the values end up being '.mif' and '.tif' (since \. has no special meaning in a double-quoted string, as does, say \n). Your regexp will then match any character followed by txt. You need to either:

    1. Put the extensions in single-quoted strings, so the backslash is preserved.
    2. Put \Q and \E in your substitution to disable pattern metacharacters (see perlre for more info if you don't know what that means). Example:
      $s1 =~ s/\Q${\TXT_EXTENSION}\E/MIF_EXTENSION/e;

    I personally recommend #2, since you want to match literal text, without metacharacters, and that's what \Q is for.

    Also, you should follow Zaxo's advice, and not dmitri's, since one will work, and one won't (you guess which is which).

    --
    3dan

      I'd prefer to write:
      MIF_EXTENSION => "[.]mif", TXT_EXTENSION => "[.]txt",
      Then you don't have to wonder how many backslashes you need, and you don't have to use \Q, \E each time you use MIF_EXTENSION or TXT_EXTENSION.

      Abigail

        Ah, but it doesn't appear that these constants are only being used as the match expression of a regex. For instance, the original code posted is trying to substitute TXT_EXTENSION for MIF_EXTENSION. I don't think the intent is to turn ".txt" into "[.]mif".

        --
        3dan

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://293323]
Approved by jdtoronto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (6)
As of 2021-04-23 06:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?