1
if ($a =~ m!^$var/!)

$var is a key in a two dimensional hash and $a is a key in another hash.

What is the meaning of this expressions?

Dada
  • 6,313
  • 7
  • 24
  • 43
  • @zdim Just write this as answere would be nice. – Andy A. Jun 04 '21 at 06:21
  • @AndyA. Sure, if you feel that that's appropriate, posted... – zdim Jun 04 '21 at 06:47
  • 1
    Should be `if ($a =~ m!^\Q$var\E/!)`. As-is, it suffers from a [code-injection bug](https://en.wikipedia.org/wiki/Code_injection) because the value of `$var` is mistakenly treated as a regex pattern. \Q\E causes the value to be converted into a regex pattern that matches the value. – ikegami Jun 04 '21 at 07:28
  • Does this answer your question? [How to use different separators (/ , |) in a regular expression](https://stackoverflow.com/questions/21335765/how-to-use-different-separators-in-a-regular-expression) – Evan Carroll Jan 06 '22 at 08:51

2 Answers2

5

This is a regular expression ("regex"), where the ! character is used as the delimiter for the pattern that is to be matched in the string that it binds to via the =~ operator (the $a here).

It may clear it up to consider the same regex with the usual delimiter instead, $a =~ /^$var\// (then m may be omitted); but now any / used in the pattern clearly must be escaped. To avoid that unsightly and noisy \/ combo one often uses another character for the delimiter, as nearly any character may be used (my favorite is the curlies, m{^$var/}). §

This regex in the question tests whether the value in the variable $a begins with (by ^ anchor) the value of the variable $var followed by / (variables are evaluated and the result used). §


Not a good choice for a variable name since $a and $b are used by the builtin sort

With the pattern prepared ahead of time the delimiter isn't even needed

my $re = qr{^$var/};

if ($string =~ $re) ...

(but I do like to still use // then, finding it clearer altogether)

Above I use qr but a simple q() would work just fine (while I absolutely recommend qr). These take nearly any characters for the delimiter, as well.


§ Inside a pattern the evaluated variables are used as regex patterns, what is wrong in general (when this is intended they should be compiled using qr and thus used as subpatterns).

An unimaginative example: a variable $var = q(\s) (literal backslash followed by letter s) evaluated inside a pattern yields the \s sequence which is then treated as a regex pattern, for whitespace. (Presumably unintended; we just wanted \ and s.)

This is remedied by using quotemeta, /\Q$var\E/, so that possible metacharacters in $var are escaped; this results in the correct pattern for the literal characters, \\s. So a correct way to write the pattern is m{^\Q$var\E/}.

Failure to do this also allows the injection bug. Thanks to ikegami for commenting on this.

zdim
  • 64,580
  • 5
  • 52
  • 81
  • :) - (But I don't like the curlies because of the quantifier.) – Andy A. Jun 04 '21 at 06:51
  • @AndyA. Alright :) You mean that it hurts readability? (Can still use it -- `m{ (.{3}) }x` ...) – zdim Jun 04 '21 at 07:03
  • OK - works as `m{.{3}}` too. And the `{}` quantifiers not seen often, so may be best. TIMTOWTDI – Andy A. Jun 04 '21 at 07:30
  • @AndyA. Right, that's what I meant -- the curlies nest (pardon my `()` in the example, accidental remainder for some curious edge-case tests I ran). Absolutely a matter of taste, agreed (except for nesting, which is a factual advantage over the single-char delims) – zdim Jun 04 '21 at 07:34
1

The match operator (m/.../) is one of Perl's "quote-like" operators. The standard usage is to use slashes before and after the regex that goes in the middle of the operator (and if you use slashes, then you can omit the m from the start of the operator). But if the regex itself contains a slash then it is convenient to use a different delimiter instead to avoid having to escape the embedded slash. In your example, the author has decided to use exclamation marks, but any non-whitespace character can be used.

Many Perl operators work like this - m/.../, s/.../.../, tr/.../.../, q/.../, qq/.../, qr/.../, qw/.../, qx/.../ (I've probably forgotten some).

Dave Cross
  • 68,119
  • 3
  • 51
  • 97