2010-02-14 10 views
13

Ho un regex:Come posso archiviare le catture da un'espressione regolare Perl in variabili separate?

/abc(def)ghi(jkl)mno(pqr)/igs 

Come dovrei catturare i risultati di ogni parentesi in 3 variabili diverse, una per ogni parentesi? In questo momento sto usando un array per catturare tutti i risultati, escono sequenziali ma poi devo analizzarli e l'elenco potrebbe essere enorme.

@results = ($string =~ /abc(def)ghi(jkl)mno(pqr)/igs); 
+0

Vuoi contare quante volte il modello è abbinato? Questo è quello che mi sembra ... – Zaid

+0

Ho bisogno di elaborare le partite – Incognito

risposta

14

La tua domanda è un po 'ambiguo per me, ma penso che si vuole fare qualcosa di simile:

my (@first, @second, @third); 
while(my ($first, $second, $third) = $string =~ /abc(def)ghi(jkl)mno(pqr)/igs) { 
    push @first, $first; 
    push @second, $second; 
    push @third, $third; 
} 
+0

Interessante. Sei sicuro che funzionerebbe? – joejoeson

+3

è un po 'prolisso. quando catturato, puoi usare i riferimenti posteriori – ghostdog74

+4

ghostdog74: questa è una questione di gusti. Se date davvero un nome alle vostre variabili $ prima e $ secondo, potreste anche usare $ 1 e $ 2, ma se date loro nomi più descrittivi, allora può migliorare la leggibilità per farlo in questo modo. –

0

Si potrebbe avere tre differenti espressioni regolari di ciascuno incentrato su gruppi specifici. Ovviamente, ti piacerebbe semplicemente assegnare diversi gruppi a diversi array nella regex, ma penso che la tua unica opzione sia quella di dividere la regex.

2

@OP, quando le parentesi vengono catturati, è possibile utilizzare le variabili $ 1, $ 2 .... questi sono backreference

$string="zzzabcdefghijklmnopqrsssszzzabcdefghijklmnopqrssss"; 
while ($string =~ /abc(def)ghi(jkl)mno(pqr)/isg) { 
    print "$1 $2 $3\n"; 
} 

uscita

$ perl perl.pl 
def jkl pqr 
def jkl pqr 
+3

Nota il suo uso del modificatore g. Sta facendo una partita globale, quindi presumo che voglia archiviare più partite. –

+2

Inoltre, $ 1 e così via non sono "backreferences", sono acquisizioni. Le parentesi e le backreferenze sono * correlate *, tuttavia. – jrockway

3

Un modo alternativo di farlo apparirebbe come la risposta di ghostdog74, ma usando un array che memorizza i riferimenti hash:

my @results; 
while($string =~ /abc(def)ghi(jkl)mno(pqr)/igs) { 
    my ($key1, $key2, $key3) = ($1, $2, $3); 
    push @results, { 
     key1 => $key1, 
     key2 => $key2, 
     key3 => $key3, 
    }; 
} 

# do something with it 

foreach my $result (@results) { 
    print "$result->{key1}, $result->{key2}, $result->{key3}\n"; 
} 

con il vantaggio principale qui di usare una singola struttura di dati, E avendo un bel ciclo leggibile.

5

A partire da 5.10, è possibile utilizzare named capture buffers così:

#!/usr/bin/perl 

use strict; use warnings; 

my %data; 

my $s = 'abcdefghijklmnopqr'; 

if ($s =~ /abc (?<first>def) ghi (?<second>jkl) mno (?<third>pqr)/x) { 
    push @{ $data{$_} }, $+{$_} for keys %+; 
} 

use Data::Dumper; 
print Dumper \%data; 

uscita:

$VAR1 = { 
      'first' => [ 
         'def' 
        ], 
      'second' => [ 
         'jkl' 
         ], 
      'third' => [ 
         'pqr' 
        ] 
     };

Per le versioni precedenti, è possibile utilizzare il seguente che evita di dover aggiungere una riga per ogni catturato buffer:

#!/usr/bin/perl 

use strict; use warnings; 

my $s = 'abcdefghijklmnopqr'; 

my @arrays = \ my(@first, @second, @third); 

if (my @captured = $s =~ /abc (def) ghi (jkl) mno (pqr) /x) { 
    push @{ $arrays[$_] }, $captured[$_] for 0 .. $#arrays; 
} 

use Data::Dumper; 
print Dumper @arrays; 

uscita:

$VAR1 = [ 
      'def' 
     ]; 
$VAR2 = [ 
      'jkl' 
     ]; 
$VAR3 = [ 
      'pqr' 
     ];

Ma mi piace mantenere i dati correlati in una singola struttura dati, quindi è meglio tornare a utilizzare un hash. Questo richiede un array ausiliario, però:

my %data; 
my @keys = qw(first second third); 

if (my @captured = $s =~ /abc (def) ghi (jkl) mno (pqr) /x) { 
    push @{ $data{$keys[$_]} }, $captured[$_] for 0 .. $#keys; 
} 

Oppure, se i nomi delle variabili sono davvero first, second ecc, o se i nomi dei buffer non contano, ma solo ordine contrario, è possibile utilizzare :

my @data; 
if (my @captured = $s =~ /abc (def) ghi (jkl) mno (pqr) /x) { 
    push @{ $data[$_] }, $captured[$_] for 0 .. $#captured; 
} 
+0

Stai solo provando a fare una copia profonda in quel primo esempio? Tirerei fuori il dclone di Storable. O questo, o il tuo esempio ha bisogno di un ciclo per creare quei valori che memorizzi in '$ dati'. :) –

+0

@brian Stavo pensando di analizzare un file in cui ogni riga ti dà un valore 'first' e un' second' e un 'terzo' e memorizza quei valori nei propri array. Confronta con l'esempio di Leon Timmerman (http://stackoverflow.com/questions/2259784/how-can-i-store-captures-from-a-perl-regular-expression-into-separate-variables/2259795#2259795) –

Problemi correlati