Есть ли простой способ локализовать (сохранить) все «магические переменные», такие как $ 1, $ и т. Д.? - PullRequest
9 голосов
/ 06 августа 2009

Я знаю, что в подпрограмме в Perl очень хорошая идея сохранить «переменную по умолчанию» $_ с local, прежде чем что-либо делать с ней, на случай, если вызывающая сторона ее использует, например ::

sub f() {
    local $_;              # Ensure $_ is restored on dynamic scope exit
    while (<$somefile>) {  # Clobbers $_, but that's OK -- it will be restored
        ...
    }
}

Теперь часто причина, по которой вы используете $_, заключается в том, что вы хотите использовать регулярные выражения, что может привести к удобным «магическим» переменным, таким как $1, $2 и т. Д. I ' Я тоже хотел бы сохранить эти переменные, но я не смог найти способ сделать это.

Все, что говорит Perlvar, это то, что @+ и @-, от которых $1 и т. Д., Кажется, зависят внутренне, ссылаются на "последние успешные суб-совпадения в текущей активной динамической области". Но даже это, кажется, расходится с моими экспериментами. Опытным путем следующий код печатает «aXaa», как я и надеялся:

$_ = 'a';
/(.)/;          # Sets $1 to 'a'
print $1;       # Prints 'a'
{
    local $_;   # Preserve $_
    $_ = 'X';
    /(.)/;      # Sets $1 to 'X'
    print $1;   # Prints 'X'
}
print $_;       # Prints 'a' ('local' restored the earlier value of $_)
print $1;       # Prints 'a', suggesting localising $_ does localise $1 etc. too

Но что меня действительно удивляет, так это то, что, по крайней мере, в моем ActivePerl 5.10.0 комментирование строки local все еще сохраняет $1 - то есть ответ «aXXa» - производится! Похоже, что лексическая (не динамическая) область действия заключенного в фигурные скобки блока каким-то образом сохраняет значение $1.

Так что я нахожу эту ситуацию в лучшем случае запутывающей и хотела бы услышать окончательное объяснение. Имейте в виду, я бы на самом деле согласился на пуленепробиваемый способ сохранения всех магических переменных, связанных с регулярными выражениями, без необходимости перечислять их все как в:

local @+, @-, $&, $1, $2, $3, $4, ...

что явно отвратительно. До тех пор я буду беспокоиться о том, что любое регулярное выражение, к которому я прикоснусь, сожжет что-то, чего не ожидал вызывающий объект.

Спасибо!

Ответы [ 3 ]

8 голосов
/ 06 августа 2009

Может быть, вы можете предложить лучшую формулировку для документации. Динамическая область действия означает все до начала включающего блока или подпрограммы, плюс все до начала этого блока или вызова подпрограммы и т. Д. за исключением , что исключены все закрытые блоки.

Еще один способ сказать это: «последние успешные подсовпадения в текущей активной динамической области» означает, что неявно существует local $x=$x; в начале каждого блока для каждой переменной.

Большинство упоминаний динамической области (например, http://perldoc.perl.org/perlglossary.html#scope или http://perldoc.perl.org/perlglossary.html#dynamic-scoping) приближаются к этому с другой стороны. Они применяются, если вы думаете об успешном регулярное выражение как неявно делает local $1 и т. д.

3 голосов
/ 06 августа 2009

Я не уверен, что есть какая-то реальная причина быть таким параноиком по поводу всех этих переменных. Мне удавалось использовать Perl в течение почти десяти лет без единой необходимости использовать явный local в этом контексте.

Ответ на ваш конкретный вопрос таков: количество цифровых переменных не является заданным (даже при том, что существует жесткое ограничение памяти на то, сколько совпадений вы можете использовать). Таким образом, невозможно локализовать их все одновременно.

1 голос
/ 07 августа 2009

Я думаю, вы слишком беспокоитесь. Лучше всего запустить оператор сопоставления, сразу же сохранить нужные значения в значимых переменных, а затем позволить специальным переменным делать все, что они делают, не беспокоясь о них:

if( $string =~ m/...(a.c).../ ) {
    my $found = $1;
    }

Когда я хочу захватить части строк, я чаще всего использую оператор соответствия в контексте списка, чтобы получить список воспоминаний обратно:

my @array = $string =~ m/..../g;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...