Perl - how variable Interpolation and backlashes (escaping) works in substitution regexes, specifically replacement part

Viewed 117

I am trying to understand what happens when a variable OR backslash OR variable containing backlash is put into a regex substitution, for example s/$var1/$var2/ or s/abc\\/xyz\\/ , etc...

This is what I tried:

use Modern::Perl; no strict;

$bs_a = "\\_a";
$bs_b = "\\_b";

$str_to_substitute = "C:\\tmp\\_a";
### I'm gonna change this string to C:\tmp\_b by regex substitution
### pattern part: $bs_a, replacement part: $bs_b
### using the whole strings instead of just s/a/b/ because for example
### I may have many such string pairs for substitutions in an external file

#1
$result = $str_to_substitute =~ s/\\_a/\\_b/r; 
say $result;  # C:\tmp\_b    ... OK

#2
$result = $str_to_substitute =~ s/\\_a/$bs_b/r; # 
say $result;  # C:\tmp\_b    ... OK

#3
$result = $str_to_substitute =~ s/$bs_a/$bs_b/r; # 
say $result;  # C:\tmp\\_b    ... why?? what is the difference between #1 and #3

#4
$result = $str_to_substitute =~ s'$bs_a'$bs_b'r; 
say $result; # $bs_a is literally '$bs_a', $bs_b also is literal

#5
$result = $str_to_substitute =~ s/$bs_a/\\_b/r;
say $result; # C:\tmp\\_b    ?? what is the difference between #1 and #5 (and #3)

What I was thinking is that the replacement doesn't do any escaping at all. (the pattern part does)

Now I am really confused and I don't understand why the results #1,#3 and the results #1,#5 are different.

  • Does anybody know why?
  • Does anybody know good easily understandable source :-) on what happens when I put variables and backlashes in the replacement part? (or in the pattern part as well but regarding substitution)
1 Answers

In cases #3 and #5, with the same output, the regex pattern is a variable that was assigned a double-quoted string, which had thus been evaluated and had undergone string interpolation; so it has one backslash character and the variable (pattern) is \_a.

So \_a from the input string is matched and replaced, while the other \ in input remains.

In case #1 the backslashes are right in the pattern, and by the details of the regex parsing one is skipped but retained. So the pattern has both \ and \_a, which are matched and replaced.

Example:

say "\\_a" =~ s{ \\_ }{X}gxr;  #--> Xa

my $p = "\\_";
say "\\_a" =~ s{ $p }{X}gxr;  #--> \Xa

The replacement side is always interpolated as a double-quoted string, even when given as/with a string literal. (Well, subject to some modifiers and delimiters.)


I'd like to add that there are various tools at our disposal that help us avoid messing with slashes, what is always a good idea. (Doubly-so for double slashes :)

For one, there are libraries for working with paths, what this seems to be about, in which case you may not need a regex at all; see File::Spec, Path::Class, and the overall handy Path::Tiny.

For regex, there is quotemeta's escapes \Q...\E, which may help to cleanly target those backslashes without worrying about their special and/or partly-special actions.

Related