Я отлаживаю некоторый код и задался вопросом, существует ли какое-либо практическое различие между 1$ и \1 в Perl regex замены
Например:
my $package_name = "Some::Package::ButNotThis";
$package_name =~ s{^(\w+::\w+)}{$1};
print $package_name; # Some::Package
Этот после строки кажется функционально эквивалентным:
$package_name =~ s{^(\w+::w+)}{\1};
Есть ли между этими двумя операторами тонкие различия? Они ведут себя по-другому в различных версиях Perl?
Во-первых, вы всегда должны использовать предупреждений при разработке:
#!/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.
Когда вы получаете предупреждение, которое вы не понимаете, добавьте диагностику :
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's 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 :
Следующие escape-последовательности доступны в конструкциях, которые интерполировать и в транслитерации…
\ 10
восьмеричное число 8
десятичное. Таким образом, заменяющая часть содержала код символа для BACKSPACE
.
Между прочим, ваш код не делает то, что вы хотите: то есть он не печатает Some :: Package
какой-то пакет вопреки тому, что написано в вашем комментарии, потому что все, что вы делаете, это заменяете Some :: Package
на Some :: Package
, не касаясь :: ButNotThis
.
Вы можете сделать:
($package_name) = $package_name =~ m{^(\w+::\w+)};
или
$package_name =~ s{^(\w+::\w+)(?:::\w+)*\z}{$1};
Из perldoc perlre:
Конструкция со скобками "( ... )" создает буферы захвата. Чтобы сослаться на на текущее содержимое буфера в дальнейшем, в пределах одного и того же шаблона, используйте \1 для первого, \2 для второго и так далее. Вне шаблона используйте "$" вместо "\".
Нотация \<цифра>
работает в определенных обстоятельствах вне соответствия. Но оно может потенциально конфликтовать с восьмеричными сокращениями. Это происходит, когда за обратной косой чертой следует более 1 цифры.