Используя Perl, как я могу построить динамическое регулярное выражение, передавая аргумент подпрограмме? - PullRequest
7 голосов
/ 01 мая 2009

Я хотел бы создать подпрограмму с динамически созданным regxp. Вот что у меня есть:

#!/usr/bin/perl

use strict;

my $var = 1234567890;


foreach (1 .. 9){
    &theSub($_);
}



sub theSub {
    my $int = @_;
    my $var2 = $var =~ m/(??{$int})/;
    print "$var2\n";
}

Похоже, что это будет работать, но, похоже, как только $ int в регулярном выражении будет вычислено впервые, оно останется навсегда.

Есть ли в любом случае что-то похожее на это, но регулярное выражение выбирает новый аргумент каждый раз, когда вызывается sub?

Ответы [ 4 ]

16 голосов
/ 01 мая 2009

Самый простой способ исправить ваш код - это добавить круглые скобки вокруг my и удалить ??{. Вот фиксированная программа:

#!/usr/bin/perl
use strict;
my $var = 1234567890;
foreach (1 .. 9){
    theSub($_);
}
sub theSub {
    my($int) = @_;
    my($var2) = $var =~ m/($int)/;
    print "$var2\n";
}

Одной из проблемных строк в вашем коде была my $int = @_, которая была эквивалентна my $int = 1, потому что она оценивала @_ в скалярном контексте, давая количество элементов в @_. Чтобы получить первый аргумент вашего подпрограммы, используйте my($int) = @_;, который оценивает @_ в контексте списка, или выберите первый элемент, используя my $int = $_[0];, или выберите + удалить первый элемент, используя my $int = shift;

Была похожая проблема в строке my $var2 =, вам также нужны скобки для оценки соответствия регулярному выражению в контексте списка, получая список ($1, $2, ...) и присваивая $var2 = $1.

Конструкция (??{...}), которую вы пытались использовать, имела эффект, противоположный тому, что вы хотели: (среди прочего) она компилировала ваше регулярное выражение в первый раз, когда оно использовалось для сопоставления. Для регулярных выражений, содержащих $ или @, но не содержащих ??{...}, Perl перекомпилирует регулярное выражение автоматически для каждого совпадения, , если не указан флаг o (например, m/$int/o).

Конструкция (??{...}) означает: используйте код Perl ... для генерации регулярного выражения и вставьте здесь это регулярное выражение. Для получения дополнительной информации выполните поиск ??{ на http://perldoc.perl.org/perlre.html. Причина, по которой это не сработало в вашем примере, заключается в том, что вам потребовался бы дополнительный слой скобок для захвата $1, но даже с my ($var2) = $var =~ m/((??{$int}))/ это не сработало бы, потому что ??{ имеет недокументированное свойство: он вызывает компиляцию своего аргумента в первый раз, когда регулярное выражение используется для сопоставления, поэтому my ($var2) = $var =~ m/((??{$int + 5}))/ всегда соответствует 6.

3 голосов
/ 02 мая 2009

Чтобы динамически передать регулярное выражение в функцию, а не динамически создавать его в функции, используйте qr //.

#!/usr/bin/perl

use strict;

my $var = 1234567890;


foreach (1 .. 9){
    &theSub(qr/$int/);
}



sub theSub {
    my($regexp) = @_;
    my($var2) = ($var =~ $regexp);
    print "$var2\n";
}

qr // принимает те же конечные аргументы, что и m //: i, m, s и x

3 голосов
/ 01 мая 2009
my $int = @_;

Это даст вам количество параметров, всегда «1» в вашем случае.

Я думаю, что вы хотите

my $int = shift;
0 голосов
/ 01 мая 2009

my $ int - это скалярный контекст, у него есть ($ int) для контекста списка, и это помещает $ _ [0] в $ int. В следующем случае только $ 10 добавляется в $ int, а остальные 11–99 теряются.

my ($ int) = (10..99); печатать $ int; 10

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