Perl - 变量插值和反斜杠(转义)如何在替换正则表达式中工作,特别是替换部分

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

我试图了解当将变量或反斜杠或包含反斜杠的变量放入正则表达式替换时会发生什么,例如 s/$var1/$var2/s/abc\/xyz\/ 等...

这是我试过的:

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)

我在想的是替换根本不进行任何转义。 (模式部分)

现在我真的很困惑,我不明白为什么结果#1、#3和结果#1、#5不一样。

在案例#3 和#5 中,具有相同的输出,正则表达式模式是一个变量,它被分配了一个双引号字符串,因此已经被评估并进行了字符串插值;所以它 有一个反斜杠 字符,变量(模式)是 \_a.

因此输入字符串中的 \_a 被匹配并替换,而输入中的其他 \ 保留。

在#1 的情况下,反斜杠在模式中是正确的,而在 details of the regex parsing 中,反斜杠被跳过但保留了下来。所以pattern同时有\\_a,它们被匹配和替换。

示例:

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

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

替换端始终插入为双引号字符串,即使给定 as/with 字符串文字也是如此。 (好吧,受一些修饰符和分隔符的影响。)


我想补充一点,我们可以使用各种工具来帮助我们避免混淆斜杠,这总是一个好主意。 (双斜线的双重如此:)

首先,有一些库可以处理路径,这似乎是关于什么的,在这种情况下,您可能根本不需要正则表达式;参见 File::Spec, Path::Class, and the overall handy Path::Tiny

对于正则表达式,有 quotemeta 的转义符 \Q...\E,这可能有助于明确定位那些反斜杠,而不必担心它们的特殊 and/or 部分特殊操作。