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

Есть ли способ оценить количество совпадений регулярного выражения Perl?

Я просматривал perldoc perlre, а также Cookings регулярных выражений и связанные с ними вопросы о переполнении стека, и я не могу найти то, что кажется очень полезным выражением: как узнать количество текущих совпадений?

Есть выражения для последнего закрытого группового совпадения ($^N), содержимого совпадения 3 (\g{3}, если я правильно понял документы), $', $& и $`. Но, похоже, я не могу использовать переменную, которая просто говорит мне, какой номер текущего совпадения.

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

Обратите внимание, что меня интересует встроенная переменная, а не обходные пути, такие как использование (${$count++}).

В контексте я пытаюсь создать регулярное выражение, которое будет соответствовать только некоторым экземплярам совпадения (например, сопоставить все вхождения символа "E", но НЕ сопоставлять вхождения 3, 7 и 10, где 3, 7 и 10 просто числа в массиве). Я столкнулся с этим, пытаясь построить более идиоматический ответ на этот SO-вопрос.

Я хочу избежать оценки регулярных выражений как строк, чтобы фактически вставить 3, 7 и 10 в само регулярное выражение.

4b9b3361

Ответ 1

Я немного поиграл с этим. Опять же, я знаю, что это не то, что вы ищете, но я не думаю, что существует так, как вы этого хотите.

У меня было две мысли. Во-первых, с split с использованием режима хранения разделителя вы получаете междоузливые биты в качестве нечетных нумерованных элементов в выходном списке. Со списком split вы подсчитаете, в каком совпадении вы находитесь, и поместите его вместе, как вам нравится:

use v5.14;

$_ = 'ab1cdef2gh3ij4k5lmn6op7qr8stu9vw10xyz';

my @bits = split /(\d+)/; # separator retention mode

my @skips = qw(3 7 10);
my $s;
while( my( $index, $value ) = each @bits ) {
    # shift indices to match number ( index = 2 n - 1 )
    if( $index % 2 and ! ( ( $index + 1 )/2 ~~ @skips ) ) {
        $s .= '^';
        }
    else {
        $s .= $value;
        }
    }

Я получаю:

ab^cdef^gh3ij^k^lmn^op7qr^stu^vw10xyz

Я думал, что мне действительно понравился мой split ответ, пока у меня не возникла вторая мысль. state работает внутри подстановки? Похоже, что он делает:

use v5.14;
$_ = 'ab1cdef2gh3ij4k5lmn6op7qr8stu9vw10xyz';
my @skips = qw(3 7 10);

s/(\d+)/
    state $n = 0;
    $n++;
    $n ~~ @skips ? $1 : '$'
    /eg;

say;

Это дает мне:

    ab$cdef$gh3ij$k$lmn$op7qr$stu$vw10xyz

Я не думаю, что вы можете стать намного проще, даже если эта волшебная переменная существовала.

У меня была третья мысль, которую я не пробовал. Интересно, работает ли state внутри утверждения кода. Возможно, но тогда мне нужно будет выяснить, как использовать один из них, чтобы сделать сбой неудачным, что на самом деле означает, что он должен пропустить бит, который мог бы совпадать. Это кажется действительно сложным, что, вероятно, то, что Бородин давил на вас, чтобы показать даже в псевдокоде.

Ответ 2

Я полностью игнорирую фактическую полезность или мудрость использования этого для другого вопроса.

Я думал, что @- или @+ могут делать то, что вам нужно, поскольку они содержат смещения нумерованных совпадений, но похоже, что механизм регулярных выражений уже знает, что будет последним индексом:

use v5.14;

use Data::Printer;

$_ = 'abc123abc345abc765abc987abc123';

my @matches = m/
    ([0-9]+)
    (?{ 
        print 'Matched \$' . $#+ . " group with $^N\n";
        say p(@+);
    })
    .*?
    ([0-9]+)
    (?{ 
        print 'Matched \$' . $#+ . " group with $^N\n"; 
        say p(@+);
    })  
    /x;

say "Matches: @matches";

Это дает строки, которые показывают последний индекс как 2, хотя он еще не соответствует $2.

Matched \$2 group with 123
[
    [0] 6,
    [1] 6,
    [2] undef
]
Matched \$2 group with 345
[
    [0] 12,
    [1] 6,
    [2] 12
]
Matches: 123 345

Обратите внимание, что первый раз, $+[2] - undef, так что он еще не заполнен. Возможно, вы сможете что-то сделать с этим, но я думаю, что, вероятно, уйти от духа вашего вопроса. Если вы действительно были в восторге, вы могли бы создать привязанный скаляр, который имеет значение последнего определенного индекса в @+, я думаю.