2012-06-05 16 views
6

Nuovo in Perl.Divisione selettiva di una stringa in Perl

Ho bisogno di analizzare un rapporto che assomigliano a questo:

[email protected]@[email protected]@[email protected] 

ho usato:

my @fields = split(/@/, $line, 6); 

maggior parte delle volte funziona benissimo, ma a volte il messaggio di errore conterrà un indirizzo email e tutto il testo dopo il simbolo @ su quell'email fino alla fine della stringa terminerà con il mio messaggio id.

Ho pensato di verificare la quantità di @s e di avere un parsing condizionale, ma c'è un modo migliore?

EDIT:

L'output desiderato è una lista di stringhe, con il messaggio di errore che contiene tutto ciò che è venuto in esso (compreso un indirizzo e-mail occasionale).

Dato che ci sono altre applicazioni che utilizzano lo stesso rapporto, non posso modificare il separatore o uscire dall'output.

linee campione sul rapporto:

[email protected]@[email protected]@440 4.4.1 Some error [email protected] 
[email protected]@[email protected]@550 5.1.1 <[email protected]>... User [email protected] 
[email protected]@[email protected]@550 5.1.1 [email protected] no such [email protected] 

contenuti attesi @Campi dopo l'analisi linea 1:

2012-05-29 
joedoe 
example.com 
AB99-5 
440 4.4.1 Some error occurred 
XYZ35 

e dopo l'analisi di linea 2:

2012-05-29 
foobar 
invalid.com 
ZZ88-6 
550 5.1.1 <[email protected]>... User Unknow 
GGH93 
+1

può chiarire che cosa l'output desiderato è? Un elenco di stringhe? – kevlar1818

+2

è un po 'difficile da progettare lì, poiché il separatore ** potrebbe ** essere parte dei dati. Se hai accesso al generatore di rapporti, penserei di sfuggire al messaggio di errore o di modificare il carattere separatore ... – kratenko

+0

Puoi dare un esempio del messaggio di errore speciale con l'indirizzo email? – simbabque

risposta

1

Simile alla risposta di daxim, ma un altro modo di scriverlo:

my $re = '^' . '([^@]*)@'x4 . '(.*)@([^@]*)$'; 
my @fields = $line =~ /$re/; 

Si consiglia inoltre di fare un po 'il controllo degli errori qui:

my @fields = $line =~ /$re/ or die "can't parse '$line'"; 
+0

Avviso: ho avuto un bug, la mia intenzione era di analizzare le due parti della posta elettronica come un unico token, quindi l'output dei nostri programmi è diverso ora. – daxim

+0

@daxim, ma questo sembra essere il risultato desiderato, almeno come dimostrato negli esempi di domande. – Qtax

+0

Hai ragione, sto facendo troppi errori oggi. – daxim

0

Il modo più semplice gestire questo sarebbe cambiare @ in un altro, delimitatore ke ;;;;

+1

Dalla domanda dell'OP: "Poiché ci sono altre applicazioni che usano lo stesso rapporto, non posso cambiare il separatore o sfuggire all'output." – kevlar1818

4

Se $ teststr contiene, ad esempio: '2012-05-29 @ emaillocalpart @ emaildomain @ customerid @ error @ me @ ssage @ messageid';

il seguente codice:

my @fields2=split('@',$teststr); 
my @[email protected][0 .. 3]; 
my $finalat=$#fields2-1; 
my $errormessage=join('@',@fields2[4 .. $finalat]); 
push(@finalfields,$errormessage); 
push(@finalfields,$fields2[$#fields2]); 

print Data::Dumper->Dump([@finalfields])."\n"; 

dà il seguente risultato:

$VAR1 = '2012-05-29'; 
$VAR2 = 'emaillocalpart'; 
$VAR3 = 'emaildomain'; 
$VAR4 = 'customerid'; 
$VAR5 = '[email protected]@ssage'; 
$VAR6 = 'messageid'; 

Scuse - è piuttosto una soluzione verbose. È anche possibile fare la stessa cosa in un'espressione regolare:

$teststr=~/(.[^@]*)@(.[^@]*)@(.[^@]*)@(.[^@]*)@(.*)@(.[^@]*)/; 
print "$1\n$2\n$3\n$4\n$5\n$6\n"; 
+0

Appena testato, funziona bene, anche se il mio rapporto reale ha 16 campi invece di 6, quindi l'unica linea apparirà un po 'più brutta. :) –

+0

@CleberGoncalves la mia risposta funzionerà per qualsiasi numero di campi, senza una regex ingombrante. Just fyi :-) – kevlar1818

1

Questo analizza correttamente gli indirizzi di posta elettronica opzionali:

$str = '[email protected]@[email protected]@550 5.1.1 <[email protected]>... User [email protected]'; 
#$str= '[email protected]@[email protected]@440 4.4.1 Some error [email protected]'; 

$str =~ s/(\<[^\>]+\>)/!!/; # replace an email address with !! 
$email = $1; # store the email 

@fields = split(/@/,$str); # split on @ 

s/!!/$email/ foreach (@fields); # find the old !! and replace with the email address 

print STDERR map { "$_ \n" } @fields; # print fields to standard error 

vederlo lavorare here. Questo presuppone che tu abbia solo una email opzionale. Con un po 'di lavoro potrebbe essere modificato per funzionare con una stringa con qualsiasi numero di email delimitate < >.

+0

Modificata la mia domanda, quando ho provato la tua soluzione ho scoperto che il rapporto potrebbe contenere anche indirizzi email non delimitati da <>. Il messaggio di errore è praticamente libero. Andrà con la regex. –

+0

+1 per i campioni di codice eseguibili su codepad. –

Problemi correlati