именованные захваты, которые совпадают более одного раза (Perl) - PullRequest
5 голосов
/ 23 ноября 2010

Когда я запускаю этот код:

$_='xaxbxc';
if(/(x(?<foo>.))+/) {
    say "&: ", $&;
    say "0: ", $-{foo}[0];
    say "1: ", $-{foo}[1];
 }

Я получаю:

&: xaxbxc
0: c
1:

Я понимаю, что это так, как это должно работать, но я хотел бы иметь возможность как-тополучить список всех совпадений ('a', 'b', 'c') вместо только последнего совпадения (c).Как я могу это сделать?

Ответы [ 5 ]

4 голосов
/ 23 ноября 2010

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

$_='xaxbxc';
while (/x(?<foo>.)/g) {
    say "foo: ", $+{foo};
}

Что именно вы пытаетесь достичь?Возможно, мы могли бы найти решение вашей реальной проблемы, даже если нет способа сделать повторные снимки.

3 голосов
/ 23 ноября 2010

В подобных ситуациях использование встроенных блоков кода обеспечивает простой выход:

my @match;
$_='xaxbxc';
if(/((?:x(.)(?{push @match, $^N}))+)/) {
    say "\$1: ", $1;
    say "@match"
}

который печатает:

$1: xaxbxc
a b c
3 голосов
/ 23 ноября 2010

Perl позволяет регулярному выражению совпадать несколько раз с переключателем «g» после конца.Каждое отдельное совпадение затем может быть зациклено, как описано в подразделе «Глобальное сопоставление» раздела Использование регулярных выражений в Perl Учебника по регулярным выражениям Perl :

while(/(x(?<foo>.))+/g){
    say "&: ", $&;
    say "foo: ", $+{foo};
}

. Это приведет к повторному выполнениюlist:

&: xa
foo: a
&: xb
foo: b
&: xc
foo: c

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

Этопохоже на вопрос, довольно похожий на этот - по крайней мере, в ответе, если не на форуме - на него ответил кто-то гораздо более компетентный в Perl, чем я: "Есть ли Perl-эквивалент Python re.findall / re.finditer(итерационные результаты регулярных выражений)? " Возможно, вы также захотите проверить ответы для этого, с более подробной информацией о правильном использовании глобальных регулярных выражений.(Perl не мой язык, я просто нездорово ценю регулярные выражения.)

1 голос
/ 23 ноября 2010

Переменная %- используется, когда у вас несколько групп с одинаковыми именами в одном и том же шаблоне, а не когда данная группа повторяется

Вот почему /(.)+/ не загружается $1 с каждым отдельным символом, только с последним.То же самое с /(<x>.)+/.Однако с /(<x>.)(<x>.)/ у вас есть две разные группы <x>, поэтому $-{x}.Рассмотрим:

% perl -le '"foobar" =~ /(?<x>.)(?<x>.)/; print "x#1 is $-{x}[0], x#2 is $-{x}[1]"'
x#1 is f, x#2 is o

% perl -le '"foobar" =~ /(?:(?<x>.)(?<x>.))+/; print "x#1 is $-{x}[0], x#2 is $-{x}[1]"'
x#1 is a, x#2 is r
0 голосов
/ 23 ноября 2010

Я не уверен, что это именно то, что вы ищете, но следующий код должен помочь.

$_='xaxbxc';
@l = /x(?<foo>.)/g;

print join(", ", @l)."\n";

Но я не уверен, что это будет работать с перекрывающимися строками.

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