2012-08-11 7 views
12

Sto studiando su perldoc perlre e su Regular Expressions Cookbook e domande correlate su Stack Overflow e non riesco a trovare quella che sembra essere un'espressione molto utile: come faccio a sapere il numero di corrispondenze correnti?Esiste un modo per valutare il numero di volte in cui una espressione regolare Perl è stata abbinata?

ci sono espressioni per l'ultimo match gruppo chiuso ($^N), contenuto di match 3 (\g{3} se ho capito correttamente la documentazione), $', $& e $`. Ma non sembra esserci una variabile che posso usare che mi dice semplicemente qual è il numero della corrispondenza attuale.

Manca davvero? Se è così, c'è qualche motivo tecnico spiegato per cui è una cosa difficile da attuare, o semplicemente non sto leggendo abbastanza attentamente il perldoc?

Si prega di notare che sono interessato a una variabile integrata, NON soluzioni alternative come l'uso di (${$count++}).

Per il contesto, sto cercando di creare un'espressione regolare che corrisponda solo ad alcune istanze di una corrispondenza (ad esempio, confronta tutte le occorrenze del carattere "E" ma NON corrisponde alle occorrenze 3, 7 e 10 dove 3, 7 e 10 sono semplicemente numeri in un array). Mi sono imbattuto in questo quando provavo a costruire una risposta più idiomatica a this SO question.

Voglio evitare di valutare regex come stringhe per inserire effettivamente 3, 7 e 10 nella regex stessa.

+0

Si prega di notare che ho bisogno del numero di partite, non # di gruppi catturati. – DVK

+0

'Si noti che sono interessato a una variabile incorporata': Se non è in perldoc perldvar, esiste? Ho assunto che perlvar contenga le variabili integrate * all * perl. – TLP

+1

Non esiste una variabile di questo tipo. perlvar non documenta tutte le variabili built-in - per esempio '@ ISA' non appare - ma tutto è documentato da qualche parte. Perl tende a non avere funzionalità nascoste. Puoi dare un esempio del problema che stai cercando di risolvere che è meglio del riferimento che dai? – Borodin

risposta

5

Ho giocato con questo per un po '. Ancora una volta, so che questo non è proprio quello che stai cercando, ma non penso che esista nel modo in cui lo vuoi.

Ho avuto due pensieri. Innanzitutto, con un split utilizzando la modalità di conservazione del separatore, si ottengono i bit interstiziali come elementi dispari nella lista di output. Con l'elenco dal split, si conta che corrispondono siete su e mettere di nuovo insieme come ti piace:

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; 
     } 
    } 

ottengo:

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

ho pensato mi è piaciuto molto il mio split risposta fino a quando ho ha avuto il secondo pensiero. state funziona all'interno di una sostituzione?Sembra che lo fa:

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

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

say; 

Questo mi dà:

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

Non credo che si può ottenere molto più semplice di quello, anche se quella variabile magia esisteva.

Ho avuto un terzo pensiero che non ho provato. Mi chiedo se state funzioni all'interno di un'asserzione di codice. Potrebbe, ma poi dovrei capire come usare uno di quelli per fare fallire una partita, il che significa in realtà che deve saltare il bit che potrebbe essere abbinato. Sembra davvero complicato, il che è probabilmente ciò che Borodin stava facendo pressioni per mostrarti anche in pseudocodice.

6

Sto completamente ignorando l'utilità effettiva o la saggezza di utilizzare questo per l'altra domanda.

ho pensato @- o @+ potrebbe fare quello che vuoi in quanto tengono gli offset delle partite numerate, ma sembra che il motore regex sa già cosa l'ultimo indice sarà:

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"; 

Questo dà stringhe che mostra l'ultimo indice come 2 anche se non corrisponde ancora a $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 

Si noti che la prima volta intorno, $+[2] è undef, in modo che uno non è stato riempito ancora. Potresti essere in grado di fare qualcosa con quello, ma penso che probabilmente stia sfuggendo allo spirito della tua domanda. Se fossi davvero di fantasia, potresti creare uno scalare legato che abbia il valore dell'ultimo indice definito in @+, suppongo.

Problemi correlati