Newsgroup: it.comp.lang.perl
Titolo: Formato CSV - regular expression

 
Ciao tutti,
volevo chiedere un piccolo aiuto per interpretare un file in formato
CSV, o presunto tale ;-)
La riga ad esempio e' come questa:
"ciao, amico", come, va, "bene,grazie"
che mi produca come risultato:
ciao, amico       come    va      bene,grazie
la semplice split /\,/, $riga_letta
non funziona ovviamente perche' mi divide anche "ciao, amico"
Io ho applicato questa funzione:
$primo, $secondo, $terzo) = split (/[(^\")*(\"$)]*,/);
In sostanza la split dovrebbe non dividere all'interno del carattere
\"
Invece l'espressione regolare che ho fatto, passata la prima lettura
di \' non interpreta altro, sono sicuro che mi manca un qualche \* ma
non so dove metterlo ;-)
|----
|Stefano Orsi
|Email: 
s.orsixxxatogcs.com
*** Remove xxx from Email address and switch at with @ ***

 CSV, o presunto tale ;-)
 perldoc Text::ParseWords
Max


Many Thanks :-)
|----
|Stefano Orsi
|Email: 
s.orsixxxatogcs.com
*** Remove xxx and switch at with @ from Email address ***

 CSV, o presunto tale ;-)
Oltre a Text::ParseWords esiste anche Text::CVS che potrebbe esserti
utile. A proposito di CVS Cpan offre anche altro.
ciao
Stefano


Ciao,
in effetti speravo di cavarmela con una reg expr., ma gia' ieri da una
ricerca su google avevo trovato altri script che forse facevano al
caso mio, ma la maggior parte erano link interrotti, non avevo pensato
a cercare su Cpan.
Grazie anche a te


 a cercare su Cpan.
Si', spesso le regexp sono troppo poco (o, meglio, e' piu' comodo
lasciare che le scrivano altri e che le mettano nei moduli). A volte
invece sono _troppo_.
Ad esempio di solito uno che ha visto un po' di Perl tende a scrivere:
foreach( @string ) {
    if ( /$substring/ ) {
        print "Trovata un'occorrenza di $expr in $_\n";
    }
}
quando invece sarebbe molto piu' efficiente usare la funzione
substr.
foreach( @string ) {
    if ( index($_, $substring) != -1 ) {
        print "Trovata un'occorrenza di $expr in $_\n";
    }
}
senza scomodare le RE che vanno compilate, eseguite e cosi' via.
ciao
Stefano

 substr.
sorry, qui intendevo dire index.


Ciao,
non e' il caso mio, ovvero uso programmare con quello che mi trovo
sottomano e che reputo piu' efficiente in quel momento, passo dal C,
al Php/MySql (con vecchie esperienze di Basic ;-)) ecc. 
Pero' non sono molto ferrato in materia perl, per cui avrei scritto
sicuramente una porzione di codice come quella di cui sopra :-)
Va be' che in questo caso le prestazioni non sono indispensabili, devo
lavorare con pochi dati e l'esecuzione media dovrebbe richiedere non
piu' di 2 o 3 sec, pero' buono a sapersi per la prossima volta.


 ciao, amico       come    va      bene,grazie
 
Se ho ben capito, il formato delle linee dovrebbe essere una sequenza di 
campi separati da delle virgole. Se un campo contiene delle virgole 
può essere incluso tra doppi apici. Se questo è il caso, lo script seguente 
fa ciò che vuoi. Tre osservazioni: 
 
1. nello script i campi sono scritti sull'uscita standard separati da " | ", ma
la cosa importante è che i campi sono nella lista @fields alla fine del  loop 
interno.
2. Lo script può essere semplificato se sei sicuro che non esistono linee
non conformi.
3. Lo script usa la variabile $', il che è una "Bad Thing©" secondo gli scritti
classici, nel senso che può rallentare l'analisi delle altre regexp. 
Sicuramente si può farne a meno...
#!/usr/bin/perl -w
while (<>) {
  chomp;
  my $riga_letta = $_;
  my @fields = ();
  while ($_) {
    if (/^\s*\"([^\"]*)\"[,]/ or /^\s*\"([^\"]*)\"$/ 
       or /^\s*([^\" ,][^,]*)[,]/ or /^\s*([^\" ,][^,]*)$/) {
      push @fields, $1;
      $_ = $';
    }
    else {
      print STDERR "malformed line: $riga_letta\n";
      @fields = ();
      last;
    }
  }
  if (@fields) {
    local $, =" | ";
    local $\ = "\n";
    print STDOUT @fields;
  }
}
-- 
Leo TheHobbit 
IRCnet #roma2
ICQ 56656060
e-mail: remove 
dont.spam.me
 from above address

 ciao, amico       come    va      bene,grazie
Apparentement ho perso i post... Mi ripeto.
Se ho capito bene la struttura del tuo file è che ogni linea contiene una lista 
di campi separati da delle virgole. Un campo può essere incluso tra doppi 
apici, il che gli permette di includere delle virgole.
In tal  caso, puoi usare lo script seguente:
#!/usr/bin/perl -w
while (<>) {
  chomp;
  my $riga_letta = $_;
  my @fields = ();
  while ($_) {
    if (/^\s*\"([^\"]*)\"[,]/ or /^\s*\"([^\"]*)\"$/
       or /^\s*([^\" ,][^,]*)[,]/ or /^\s*([^\" ,][^,]*)$/) {
      push @fields, $1;
      $_ = $';
    }
    else {
      print STDERR "malformed line: $riga_letta\n";
      @fields = ();
      last;
    }
  }
  if (@fields) {
    local $, =" | ";
    local $\ = "\n";
    print STDOUT @fields;
  }
}
Tre osservazioni su questo script:
1. lo script mette i campi in un vettore @fields per poi stamparli sull'uscita
standard separandoli con " | ".
2. Lo script può essere semplificato se sei sicuro che il file non contiene
linee malformate
3. Lo script utilizza la variabile predefinita $', il che è una "Bad Thing©" in 
quanto appesantisce la valutazione di _tutte_ le regexp dello script. Se non
hai altre regexp questo non è un problema, sennò lo script può essere 
riscritto in modo da evitare tale variabile. 



Ciao,
anche io non scherzo, non ti ho nemmeno ringraziato.
Lo faccio adesso, e scusa per il ritardo.
