chris01
chris01

Reputation: 12321

Perl: Regex with Variables inside?

Is there a more elegant way of bringing a variable into a pattern than this (put the patterin in a string before instead of using it directly in //)??

my $z = "1";  # variable
my $x = "foo1bar";

my $pat = "^foo".$z."bar\$";   
if ($x =~ /$pat/)
{
  print "\nok\n";
}

Upvotes: 2

Views: 1959

Answers (1)

zdim
zdim

Reputation: 66873

Need to delimit the variable's name so to be recognized inside a string, /^foo${z}bar$/

Use the qr operator to build a variable with a regex pattern

my $pat = qr/^foo${z}bar$/;

If the delimiters are ' the variables aren't interpolated, just like for normal strings.

This operator is the best way to build patterns ahead of time as it builds a proper regex pattern, accepting everything that one can use in a pattern in a regex. It also takes modifiers, so for one the above can be written as

my $pat = qr/^foo $z bar$/x;

for a little extra clarity (but careful with omitting those {}).

The initial description from the above perlop link (examples and discussion follow):

qr/STRING/msixpodualn

This operator quotes (and possibly compiles) its STRING as a regular expression. STRING is interpolated the same way as PATTERN in m/PATTERN/. If "'" is used as the delimiter, no variable interpolation is done. Returns a Perl value which may be used instead of the corresponding /STRING/msixpodualn expression. The returned value is a normalized version of the original pattern. It magically differs from a string containing the same characters: ref(qr/x/) returns "Regexp"; however, dereferencing it is not well defined (you currently get the normalized version of the original pattern, but this may change).

The same goes for normal strings, "^foo${z}\$", and most patterns work. But we often need to do more work since many regex patterns in a double-quoted string have their own meaning.

An example are escaped sequences, which are treated as string "escapes" and interpolated as such, or attempted (\s, \w... fail with warnings for not being recognized as valid escapes). As they need be passed to the regex untouched anyway most escapes need be escaped (\\w), depriving \ of its special meaning -- but some (\x27) need to stay as they are!

Single-quoting the string solves this (no need to escape things) but then variable interpolation is off. The qr has none of these complications as it's meant for a regex pattern.


Once a variable is getting interpolated it may be a good idea to escape special characters that may be hiding in it, that could throw off the regex, using quotemeta-based \Q ... \E

my $pat = qr/^foo \Q$z\E bar$/x;

If this is used then the variable name need not be delimited either

my $pat = qr/^foo\Q$z\Ebar$/;

Thanks to Håkon Hægland for bringing this up.

Upvotes: 7

Related Questions