2010-02-21 9 views
56

Sto provando a usare regex in Perl. Quello che mi chiedevo era se fosse possibile memorizzare tutte le corrispondenze nell'espressione in un array? So che posso usare quanto segue: ($1,...,$n) = m/expr/g; ma sembra che possa essere usato solo se si conosce il numero di partite che si stanno cercando. Ho provato my @array = m/expr/g; ma non sembra funzionare.Come posso memorizzare le catture di espressioni regolari in una matrice in Perl?

Grazie per il vostro aiuto!

+8

spiegare "doesn sembra funzionare ", preferibilmente con un esempio reale. che * dovrebbe * funzionare. – ysth

risposta

70

Se si sta eseguendo una corrispondenza globale (/g), la regex nel contesto dell'elenco restituirà tutte le corrispondenze acquisite. Semplicemente fare:

my @matches = ($str =~ /pa(tt)ern/g) 

Questo comando, ad esempio:

perl -le '@m = ("foo12gfd2bgbg654" =~ /(\d+)/g); print for @m' 

Dà l'output:

12 
2 
654 
+10

non necessario per(), = ~ è un operatore con precedenza alta – ysth

+3

Assicurati di utilizzare "se provi questo in Windows 'shell', in questo modo, perl -le" @m = ('foo12gfd2bgbg654' = ~/(\ d +)/g); stampa per @m "altrimenti si ottiene un errore, poiché la shell usa" come delimitatore di stringhe – roamcel

+10

@ysth. È molto meno leggibile senza parentesi. – MikeKulls

15

Vedi la voce manuale perldoc perlop sotto "Corrispondenza in List contesto":

Se l'opzione/g non viene utilizzata, m // in lista contesto restituisce un elenco costituito dalle sottoespressioni corrispondenti alle parentesi nel modello, ad esempio, ($ 1, $ 2, $ 3 ...)

Il modificatore/g specifica la corrispondenza del modello globale, ovvero la corrispondenza di più tempi come possibili all'interno della stringa. Il modo in cui si comporta dipende dal contesto. Nel contesto dell'elenco, restituisce un elenco delle sottostringhe corrispondenti a qualsiasi parentesi di acquisizione nell'espressione regolare. Se non ci sono parentesi, restituisce un elenco di tutte le stringhe corrispondenti, come se ci fossero parentesi attorno all'intero pattern.

Si può semplicemente prendere tutte le partite assegnando ad un array, o comunque di eseguire la valutazione nel contesto di lista:

my @matches = ($string =~ m/word/g); 
16

A volte è necessario per ottenere tutte le partite a livello globale, come PHP di preg_match_all fa. Se è il vostro caso, allora si può scrivere qualcosa come:

# a dummy example 
my $subject = 'Philip Fry Bender Rodriguez Turanga Leela'; 
my @matches; 
push @matches, [$1, $2] while $subject =~ /(\w+) (\w+)/g; 

use Data::Dumper; 
print Dumper(\@matches); 

Esso stampa

$VAR1 = [ 
      [ 
      'Philip', 
      'Fry' 
      ], 
      [ 
      'Bender', 
      'Rodriguez' 
      ], 
      [ 
      'Turanga', 
      'Leela' 
      ] 
     ]; 
+3

Tecnica molto maneggevole; c'è un modo per generalizzare questo, nel caso in cui il numero di gruppi di cattura non sia noto?Sembra che potresti aver bisogno di una variabile di array speciale che comprende '($ 1, $ 2, ...)', ma non sono riuscito a trovare una cosa del genere. – mklement0

8

Credo che questo sia un esempio di auto-esplicativo. Nota /g modificatore nella prima regex:

$string = "one two three four"; 

@res = $string =~ m/(\w+)/g; 
print Dumper(@res); # @res = ("one", "two", "three", "four") 

@res = $string =~ m/(\w+) (\w+)/; 
print Dumper(@res); # @res = ("one", "two") 

Ricordate, è necessario assicurarsi che il valore assegnabile è nel contesto di lista, il che significa che è necessario circondare valori scalari con parentesi:

($one, $two) = $string =~ m/(\w+) (\w+)/; 
Problemi correlati