Подтвердить что ты не робот

Perl: Почему eval '/(...)/' не устанавливает $1?

Если совпадение регулярных выражений происходит внутри eval, изменения в связанных с захватом переменных ($ 1 и т.д.) не отображаются во внешней среде. Это ошибка?

perlop и perlre, похоже, не упоминают о таком ограничении.

Например:

 use strict; use warnings;
 $_ = "hello";
 eval '/(.*)/';
 print "GOT: $1\n";

дает:

Use of uninitialized value $1 in concatenation (.) or string at -e line 1.
GOT:

Более краткая демонстрация:

perl -we '$_="foo"; eval q(/(.*)/;) ; print "GOT:$1\n";'
4b9b3361

Ответ 1

Доказательство документации, что local переменные являются проблемой, находится в perlvar из 5.14.0:

Эти переменные доступны только для чтения и с динамической областью, если не указано иное.

Динамический характер переменных регулярного выражения означает, что их значение ограничено блоком, в котором они находятся [...]

Обратите внимание, что этот бит документации отсутствует на 5.12.4 perldoc.


Проблема заключается в local переменных. Моя копия perldoc -f eval (5.12.4) гласит:

The assignment to [email protected] occurs before restoration of localised
variables, which means a temporary is required if you want to
mask some but not all errors: [...]

В manpage не делается явный оператор для всех таких специальных глобальных переменных (например, $1, $& и, возможно, другие), но локальная локализация и последующее восстановление - это то, что, кажется, происходит здесь.

Переменные присваиваются внутри eval, а исходные значения восстанавливаются после того, как остался блок eval.

use strict; use warnings;
use Test::More;
use constant V => 'hello';

$_ = V;

note '*** block eval';
eval {
        is $_, V, 'input ok';
        /(.*)/;
        is $&, V, 'in eval'; is $1, V, 'in eval';
};
is $&, V, 'after eval'; is $1, V, 'after eval';

note '*** without eval';
is $_, V, 'input ok';
/(.*)/;
is $&, V; is $1, V;

done_testing;

Ответ 2

Фактический вопрос уже дан, поэтому ответьте, как вы достигаете задачи.

Просто используйте возвращаемые значения eval, которые, в свою очередь, используют возвращаемые значения оператора соответствия. $1 отстой, избегайте.

use strict; use warnings;
$_ = "hello";
my @r = eval '/(.*)/';
# (
#     "hello"
# )

Ответ 3

Любые лексические переменные, объявленные в пределах eval, будут потеряны после окончания eval.