1

I want to ensure variables are interpolated as they are within perl regular expressions. Would rather avoid binding over to other variables in a cascate of "ifs" that would rarely need that variable throughout the code execution. How could I ensure I used the variable?

use strict;
use warnings FATAL => "all";

$_="botherther";

my $bo = "bother";
if (/^$bother$/) { # want to consider just $bo here!
  print("Undestood regex as /($bo)ther/.\n");
} else {
  print("Couldnt discern variable.\n");
}

my $bi = { bo => "the" };
if (/^bo$bi->{bo}[r]ther$/) { # now, $bi->{bo} only
  print("Discerned /bo($bi->{bo})[r]/\n");
} else {
  print("Couldnt discern variable.\n");
}

I'm not able to find a way to wrap the variables properly within the regex. Of course I could just my $bi_resolved = $bi->{bo} or fill the regex with null-thingies (like [] or ()), but this does not feel like a proper separator.

For clarity:

  1. I wanted to expand $bo into bother to get the /botherther/ string in the first match.
  2. I wanted to expand $bi->{bo} into the to get <bo><the><[r]ther>, again /botherther/ in the second match.
  3. Important noting, I don't care for the sake of this context, about the escapes \Q and \E, "I am assuming there's never metacharacters within the variables".

I have searched thru questions, read documentation, and couldn't find an answer for this. Wrapping in ${} didn't work for me (that's trying to dereference stuff). So, while searching I feel I am just barking at the wrong tree... It's simply unbelievable nobody ever needed to ask something like that around perlmonks or stackoverflow. I'm probably just looking for the wrong keywords here. :/

Avenger
  • 177
  • 1
  • 8
  • For `/^$bother$/` I could make do with `/^${bo}ther$/`. But for `$bi->{bo}`, just `${bi->{bo}}` (i.e. wrapping in `${}`) doesn't do, errors with _"Can't use bareword ("bi") as a HASH ref"_. – Avenger Dec 14 '19 at 20:47
  • That's because `$BLOCK[...]` is an array lookup, where `BLOCK` is expected to return a reference to an array – ikegami Dec 15 '19 at 13:57
  • where am I using `$BLOCK[...]` in my code?.. I know I could use something like `(?{ code })` (re-eval code), but to me it would be too overkill, and having a temporary simpler variable would be better. **re-eval** code would be great for a very complex match I won't require to do a lot of times in a program, I guess. – Avenger Dec 18 '19 at 18:22
  • Re "*where am I using $BLOCK[...] in my code?*", You didn't show it, but you said you tried `/^bo${bi->{bo}}[r]ther$/` ("*Wrapping in `${}` didn't work for me*") – ikegami Dec 18 '19 at 18:37

2 Answers2

2

There are four main ways:

  • Use /x ($bi{bo} [r] instead of $bi{bo}[r])
  • Use curlies around the variable name (${bo}ther instead of $bother)
  • Escape the next character ($bo\->[0] instead of $bo->[0])
  • Isolation via parens or some other means ((?:$bi{bo})[r] instead of $bi{bo}[r])[1]

That said, if you're interpolating text (rather than a regex pattern), you should be using \Q$var\E anyway, making the problem moot.

use strict;
use warnings FATAL => "all";

$_="botherther";

my $bo = "bother";
if (/^\Q$bo\Ether$/) { # want to consider just $bo here!
  print("Understood regex as /^botherther\$/.\n");
} else {
  print("Couldn't discern variable.\n");
}

my $bi = { bo => "the" };
if (/^bo\Q$bi->{bo}\E[r]ther$/) { # now, $bi->{bo} only
  print("Discerned /^bothe[r]ther\$/\n");
} else {
  print("Couldn't discern variable.\n");
}

Thanks to @ysth for improvements.


  1. Imposes a small run-time penalty.
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • I may want to interpret the variable, so I emphasized in my item (3) that I was not looking for a \Q \E solution. Sorry if I made a long question and you didn't feel like reading it all. Here's what I posted: _"Important noting, I don't care for the sake of this context, about the escapes \Q and \E, "I am assuming there's never metacharacters within the variables"."_. Your first suggestion drops the `->` of the variable, I was looking for a way to arbitrarily wrap the variable name, which the curly brackets didn't do. Anyways, thanks for the collaboration. – Avenger Dec 18 '19 at 18:11
  • Re "*I am assuming there's never metacharacters within the variables*", That's a stupid assumption to make. There's no reason to open yourself up to code injection bugs/attacks just to avoid `\Q...\E`, especially when the alternative (`(?:...)`) is just one character shorter. – ikegami Dec 18 '19 at 18:42
  • I meant for the sake of my question, this very important and relevant fact is not taken into account...... I already know what the `\Q` and `\E` does and their application is not the point of the question.... – Avenger Jan 08 '20 at 02:04
1

To separate interpolated variable names from other text is usually
done like ${name}

So, a part of the code sample becomes

use strict;
use warnings;

$_="botherther";

my $bo = "bother";
if (/^${bo}ther$/) { # want to consider just $bo here!
  print("Undestood regex as /${bo}ther/.\n");
} else {
  print("Couldnt discern variable.\n");
}

A good way to test stuff is to put it into a qr// then print it out :

my $rx = qr/^${bo}ther$/;
print $rx;

Per @choroba :

As far as the regex goes, it looks like the variable can also be wrapped
in a group without modification and should cover all cases.
It's really just a parsing thing. If Perl can distinquish delimiters to get
a variable notation in a string, it will interpolate it.

Like (?:$bo) or (?:$bi->{bo})
but it will be wrapped inside a residual group.

  • 1
    what about the `$bi->{bo}` bit (which shouldn't consider the `[r]` bit)? – Avenger Dec 14 '19 at 20:51
  • A hash reference ? Probably want to assign it to a `my $bo = $bi->{bo};` bit. Keep dereferencing it untill you get a scalar. –  Dec 14 '19 at 20:53
  • 4
    `/^bo(?:$bi->{bo})[r]ther$/` – choroba Dec 14 '19 at 20:55
  • As far as the regex goes, it looks like the variable can be wrapped in a group without modification and should cover all cases. Like `(?:$bo)` or `(?:$bi->{bo})` but it will be wrapped inside a residual group.. –  Dec 14 '19 at 21:08
  • 1
    About the `$bo = $bi->{bo}` I mentioned in the question I had reasons it wasn't desirable in my case (look up `$bi_resolved` in the question). The untracked-grouping might be the way to go and fulfill my needs. Wouldn't it be reasonable if @choroba nailed the answer here? – Avenger Dec 14 '19 at 21:47
  • 2
    The important thing is to learn; who earns the XP is insignificant :) – choroba Dec 14 '19 at 22:19
  • instead of a non-capturing group, you can \-escape the -. or add an empty comment `(?#)` – ysth Dec 15 '19 at 02:09
  • @ysth, I wanted to consider the dereferencing in that case, I wanted to use `$bi->{bo}` and keep as regex the `[r]` bit (which could be something like `[rR]` to make more sense). The point was, it could be undestand by perl as a continuation of the variable, as an array index refernce `$bi->{bo}[r]` (which would result in a syntax error, in the example). – Avenger Dec 18 '19 at 18:17