В чем разница между использованием $1 vs\1 в Perl-regex-заменах?

Я отлаживаю некоторый код и задаюсь вопросом, существует ли какая-либо практическая разница между $1 и \1 в Perl-подстановках регулярных выражений

Например:

my $package_name = "Some::Package::ButNotThis";

$package_name =~ s{^(\w+::\w+)}{$1};  

print $package_name; # Some::Package

Эта следующая строка выглядит функционально эквивалентной:

$package_name =~ s{^(\w+::w+)}{\1};

Существуют ли тонкие различия между этими двумя утверждениями? Они ведут себя по-разному в разных версиях Perl?

Ответ 1

Во-первых, вы должны всегда использовать warnings при разработке:

#!/usr/bin/perl

use strict; use warnings;

my $package_name = "Some::Package::ButNotThis";

$package_name =~ s{^(\w+::\w+)}{\1};

print $package_name, "\n";

Вывод:

\1 better written as $1 at C:\Temp\x.pl line 7.

Когда вы получите предупреждение, которое вы не понимаете, добавьте diagnostics:

C:\Temp> perl -Mdiagnostics x.pl
\1 better written as $1 at x.pl line 7 (#1)
    (W syntax) Outside of patterns, backreferences live on as variables.
    The use of backslashes is grandfathered on the right-hand side of a
    substitution, but stylistically it better to use the variable form
    because other Perl programmers will expect it, and it works better if
    there are more than 9 backreferences.

Почему он работает лучше, если имеется более 9 обратных ссылок? Вот пример:

#!/usr/bin/perl

use strict; use warnings;

my $t = (my $s = '0123456789');
my $r = join '', map { "($_)" } split //, $s;

$s =~ s/^$r\z/\10/;
$t =~ s/^$r\z/$10/;

print "[$s]\n";
print "[$t]\n";

Вывод:

C:\Temp> x
]
[9]

Если это не разъясняет это, взгляните на:

C:\Temp> x | xxd
0000000: 5b08 5d0d 0a5b 395d 0d0a                 [.]..[9]..

См. также perlop:

В конструкциях, которые интерполируют и транслитерируют & hellip, доступны следующие escape-последовательности;

\10 восьмеричный 8 десятичный. Итак, запасная часть содержала код символа для BACKSPACE.

NB

Кстати, ваш код не делает то, что вы хотите: то есть он не будет печатать Some::Package какой-либо пакет, в отличие от вашего комментария, потому что все, что вы делаете, заменяет Some::Package на Some::Package, не касаясь ::ButNotThis.

Вы можете:

($package_name) = $package_name =~ m{^(\w+::\w+)};

или

$package_name =~ s{^(\w+::\w+)(?:::\w+)*\z}{$1};

Ответ 2

Из perldoc perlre:

Конструкция брекетинга "(...)" создает буферы захвата. Ссылаясь на          текущее содержимое буфера позже, в рамках одного и того же шаблона, используйте          \ 1 для первого, \2 для второго и т.д. Вне матча используйте           "$" вместо "\".

Обозначение \<digit> работает в определенных обстоятельствах вне матча. Но это может потенциально столкнуться с восьмеричными побегами. Это происходит, когда обратная косая черта сопровождается более чем 1 цифрой.