Ошибка в Perl или я не понимаю что-то о сопоставлении регулярных выражений и переменных perl? - PullRequest
1 голос
/ 17 июня 2011

Долгое время я всегда думал, что параметры в сабвуферах Perl передаются по значению. Теперь я столкнулся с чем-то, чего я не понимаю:

use strict;
use warnings;

use Data::Dumper;

sub p {
    print STDERR "Before match: " . Data::Dumper->Dump([[@_]]) . "\n";
    "1" =~ /1/;
    print STDERR "After  match: " . Data::Dumper->Dump([[@_]]) . "\n";
}

my $line = "jojo.tsv.bz2";

if ($line =~ /\.([a-z0-9]+)(?:\.(bz2|gz|7z|zip))?$/i) {
    p($1, $2 || 'none');
    p([$1, $2 || 'none']);
}

При первом вызове p () и после выполнения соответствия регулярному выражению значения в @_ станут undefs. При втором вызове все в порядке (значения, переданные в качестве ссылки на массив, не затрагиваются).

Это было протестировано с версиями Perl 5.8.8 (CentOS 5.6) и 5.12.3 (Fedora 14).

Вопрос в том, как это могло случиться, что соответствие регулярному выражению уничтожает содержимое @_, которое было построено с использованием $ 1, $ 2 и т. Д. (Другие значения, если вы их добавите, не затрагиваются)?

Ответы [ 3 ]

15 голосов
/ 17 июня 2011

Страница man perlsub говорит:

Массив @_ является локальным массивом, но его элементы являются псевдонимами для фактических скалярных параметров.

Таким образом, когда вы передаете $1 подпрограмме, внутри этой подпрограммы $_[0] есть псевдоним для $1, а не копия из $1.Поэтому он изменяется в соответствии с регулярным выражением в вашей p.

В общем, начало каждой подпрограммы Perl должно выглядеть примерно так:

my @args = @_;

... или это:

my ($arg1, $arg2) = @_;

... или это:

my $arg = shift;

И любое регулярное выражение для захвата должно использоваться следующим образом:

my ($match1, $match2) = $str =~ /my(funky)(regexp)/;

Без таких дисциплин вы, скорее всего,быть сведенным с ума тонкими ошибками.

4 голосов
/ 17 июня 2011

Как и предполагалось, копирование аргументов в каждую подпрограмму является хорошей идеей (хотя бы для документирования того, чем они являются, путем присвоения им названия без знаков препинания).

Однако, это также хорошая идея, чтобы никогда не пропускатьглобальные переменные;пройти "$1", "$2", а не $1, $2.(Это относится и к таким вещам, как $DBI::errstr).

0 голосов
/ 17 июня 2011

Я не совсем уверен, почему это происходит, но я бы сказал, что вы должны использовать что-то вроде моего $ arg1 = shift;мой $ arg2 = смещение;и используйте $ arg1 и $ arg2 в своей подпрограмме.

Используя отладчик perl, вы увидите, что @_ выглядит по-разному в 2 дополнительных вызовах:

1-й вызов: до совпадения:

x @_
0  'tsv'
1  'bz2'

После совпадения:

x @_
0  undef
1  undef

Я думаю, что это было переписано в матче.

2-й вызов: до матча:

x @_
0  ARRAY(0xc2b6e0)
    0  'tsv'
    1  'bz2'

После матча:

x @_
0  ARRAY(0xc2b6e0)
    0  'tsv'
    1  'bz2'

Итакможет быть, это не было перезаписано из-за другой структуры (?).

Надеюсь, это немного поможет.

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