/ / catture con nome che corrispondono più di una volta (Perl) - regex, perl

le acquisizioni denominate che corrispondono più di una volta (Perl) - regex, perl

Quando eseguo questo codice:

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

Ottengo:

&: xaxbxc
0: c
1:

Capisco che è così che dovrebbe funzionare, ma vorrei poter in qualche modo ottenere l'elenco di tutte le partite ("a", "b", "c") anziché solo l'ultima partita (c). Come posso fare questo?

risposte:

3 per risposta № 1

In situazioni come queste, l'uso di blocchi di codice incorporati fornisce una soluzione semplice:

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

che stampa:

$1: xaxbxc
a b c

4 per risposta № 2

Non credo che ci sia un modo per farlogenerale (per favore correggimi se sbaglio), ma è probabile che ci sia un modo per raggiungere lo stesso obiettivo finale in situazioni specifiche. Ad esempio, questo funzionerebbe per il tuo esempio di codice specifico:

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

Cosa stai cercando di realizzare esattamente? Forse potremmo trovare una soluzione al tuo vero problema anche se non c'è modo di ripetere le acquisizioni.


3 per risposta № 3

Perl consente a un'espressione regolare di corrispondere più volte con l'interruttore "g" oltre la fine. Ogni singola corrispondenza può quindi essere ripetuta, come descritto nella sottosezione Global Matching di Utilizzo delle espressioni regolari nella sezione Perl del Tutorial Perl Regex:

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

Questo produrrà un elenco iterato:

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

Che non è ancora quello che vuoi, ma lo è davverovicino. Combinando una regex globale (/ g) con te, una regex locale precedente probabilmente lo farà. Generalmente, crea un gruppo di acquisizione attorno al tuo gruppo ripetuto, quindi analizza di nuovo solo quel gruppo con una regex globale che rappresenta solo una singola iterazione di quel gruppo e itera su di esso o usalo come un elenco.

Sembra una domanda abbastanza simile a questa - almeno nella risposta, se non nel forum - ha ricevuto risposta da qualcuno molto più competente in Perl di me: "Esiste un equivalente Perl di Python" re.findall / re.finditer (risultati regex iterativi)? " Potresti voler controllare anche le risposte, con maggiori dettagli sull'uso corretto delle regex globali. (Perl non è la mia lingua, ho solo un malsano apprezzamento per le espressioni regolari.)


1 per risposta № 4

Il %- viene utilizzata quando si dispone di più di uno stesso gruppo denominato nello stesso modello, non quando un determinato gruppo viene ripetuto.

Ecco perchè /(.)+/ non si carica $1 con ogni personaggio separato, solo con l'ultimo. Lo stesso con /(<x>.)+/. Tuttavia, con /(<x>.)(<x>.)/ ne hai due diversi <x> gruppi, quindi $-{x}. Tenere conto:

% 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 per risposta № 5

Non sono sicuro che sia esattamente quello che stai cercando, ma il seguente codice dovrebbe fare il trucco.

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

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

Ma non sono sicuro che funzionerebbe con stringhe sovrapposte.