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
| [reply] [d/l] |
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. | [reply] [d/l] |
|
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
| [reply] |
|
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";
| [reply] [d/l] [select] |
|
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
| [reply] [d/l] [select] |
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:
- Put the extensions in single-quoted strings, so the backslash is preserved.
- 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
| [reply] |
|
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 | [reply] [d/l] |
|
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
| [reply] |
|
|