Есть ли простой способ получить список всех успешных захватов из регулярного выражения до 5.10? - PullRequest
4 голосов
/ 18 марта 2010

Я знаю правильный способ сделать это, если у меня есть Perl 5.10, это использовать именованные захваты и values %+, но в Perl 5.8.9 и как я могу получить список успешных захватов? Я придумал два метода, которые оба просто ужасны:

#you need to list each possible match
my @captures = grep { defined } ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16);

и

#ew, I turned on symbolic references 
{
    no strict 'refs';
    my @captures = map { defined $+[$_] ? $$_ : () } 1 .. $#+;
}

Существует третий вариант, который я обнаружил, включающий (?{}), но он требует глобальных переменных (потому что закрытие происходит во время компиляции) и переводит регулярное выражение из достаточно чистого в безбожный беспорядок.

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

Я, очевидно, пропустил важную часть информации. Я использую регулярное выражение в скалярном контексте вместе с утверждением \G, потому что регулярное выражение может меняться между совпадениями (один из токенов меняет способ, которым вы выбираете токены из строки). Для примера кода, написанного для Perl 5.10, см. этот вопрос , в частности этот ответ .

Ответы [ 2 ]

1 голос
/ 18 марта 2010

Вы можете использовать @+ и @-, как в

substr $var, $-[N], $+[N] - $-[N] # corresponds to $N

Но, как было сказано ранее, если вы можете, используйте форму @list = grep defined, $var =~ /regex/.

0 голосов
/ 18 марта 2010

В следующем решении используется строка eval, но я думаю, что она довольно безопасна.

Обновление: Может быть, я все еще что-то упускаю, но AFAICS, тот факт, что шаблон использует \G и совпадение в скалярном контексте, имеет значение только потому, что результаты сопоставления не могут быть назначены @matches напрямую.

Фактически, приведенный ниже метод является разновидностью второго предложенного метода в часах. ' ОП, где он использовал символические ссылки. ИМХО, использовать символьные ссылки или строку eval хорошо, потому что они происходят очень хорошо определенным образом.

#!/usr/bin/perl

use strict; use warnings;

my $text = <<EOT;
a
2 b
3 c 3
EOT

my $re = qr/([a-z])/;

while ( $text =~ /$re/g  ) {
    my @matches = grep defined, map eval "\$$_", 1 .. $#-;
    print "@matches\n";
    if ( $matches[0] eq 'a' ) {
        $re = qr/\G\s+([0-9])\s+([a-z])/;
        next;
    }
    if ( defined $matches[1] and $matches[1] eq 'b' ) {
        $re = qr/\G\s+([0-9])(?: ([a-z]))(?: ([0-9]))/;
        next;
    }
}

Выход:

C:\Temp> jj
a
2 b
3 c 3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...