Newsgroup: it.comp.lang.perl
Titolo: scansione file riga per riga + query (lunghetto)

sto provando la scansione di un file di testo riga per riga per poi 
inserire alcuni valori (se soddisfano le regexp) in un database
il file e' piu' o meno fatto cosi'
ab.qualcosa
   Ragione Sociale
   20021213    
12.34.56.78/10
    NOTE
   20030915    
78.65.43.21/20
    NOTE
bc.qualcosa
   Rag Sociale
   20021218    12.34.566.78/30    NOTE
   20030915    78.65.443.21/50    NOTE
   20040912    72.644.43.21/10    NOTE
e via cosi' dove l'unica cosa costante e' la prima e la seconda riga 
(mentre per quanto riguarda il gruppetto con le NOTE potrebbe essere 0 
o piu' righe)
la mia idea di partenza era quella di fare una scansione riga per riga 
e poi memorizzare, prima di passare all'iterazione successiva, le 
variabili dominio, rag_soc e classe_ip
il fatto e' pero' che devo riuscire ad abbinare, nel database, le 
classi_ip allo stesso nome+dominio in questa maniera:
dominio      |    nome_isp   |   classe_ip
ab.qualcosa  |   AB. s.p.a   |  
12.34.56.78/10
ab.qualcosa  |   AB. s.p.a   |  
78.65.43.21/20
bc.qualcosa  |   BC. & Co.   |  12.34.566.78/30
...
etc
come posso fare?
grazie
-- 
Umin
n. p.: Ivano Fossati - Buontempo

classi_ip allo stesso nome+dominio in questa maniera:
Direi che può andare bene, se puoi distinguere a che gruppo appartiene la
riga in base alle specifiche sopra: se inizia con spazi o tabulazioni
(/^\s+/) è del secondo o terzo tipo (ragione sociale o ip), se no è del
primo. Fra il secondo e il terzo, puoi distinguerli se il terzo ha un
numero di 8 cifre dopo gli spazi iniziali (/^\s+[0-9]{8}/).
Se la riga è del primo tipo, aggiorni la variabile dominio, se del secondo
aggiorni la variabile rag_soc, se del terzo stampi i tre campi dominio,
rag_soc e ip (dopo naturalmente aver fatto uno split della riga per
recuperare l'ip). Questo perché hai detto che il gruppetto con le NOTE
potrebbe essere "0 o piu' righe": se fosse sempre presente, l'analisi
sarebbe più semplice.
Un'alternativa potrebbe essere prendere un intero blocco alla volta, invece
che una sola riga ($/ = ""). In questo caso però direi che non c'è un gran
guadagno (se non ci fosse la terza riga vuota in mezzo, sarebbe più comodo
fare così).
Ciao.

 fare così).
avevo pensato di ragionare a blocchi, sarebbe piu' semplice ma
1) sono alle prime armi (ho iniziato ieri con perl e regexp)
2) c'e' quel problema delle 0 righe in caso di provider chiuso...
:(
-- 
Umin
n. p.: Luciano Ligabue - Il Giorno dei giorni

    20040912    72.644.43.21/10    NOTE
ho scritto questo:
while ($riga = <SORG>) {
		#scansione della riga in cerca del dominio
	SWITCH: {
			print "\ndominio: ".$1, if $riga =~ /^(it\.\D+)$/;
			print "\tnome isp: ".$1."\n", if $riga =~ /((\t|\s)+[A-Z][a-z]\D+)/;
			print "\tclasse ip: ".$1."\n", if $riga =~ /((\d|\.)+\/\w{2}\t)/;
		}
}
funziona abbastanza bene ma non benissimo
l'output infatti e':
dominio: it.bema
        nome isp:     Sinergia S.r.l.
        classe ip: 62.101.128/19
dominio: it.bentec
        nome isp:     Bentec S.p.A.
        classe ip: 217.149.80/20
dominio: it.bergamocom
        nome isp:     Bergamocom Telecomunicazioni srl
        classe ip: 80.85.240/20
ed e' giustissimo ma dopo comincia a svalvolare diventando
dominio: it.worldonline
        nome isp:     World Online S.r.l. (closed)
dominio: it.zucchetti
        classe ip: 62.108.224/19
dominio: it.zz
        nome isp:  Last Resort Internet Registry for Italy (closed)
        nome isp:  Middle East)
        classe ip: 62.68.96/19
        classe ip: 217.23.32/20
        nome isp:     Al Saria LeTarasoul Al Moutayat Co. LTD.
        classe ip: 80.89.192/20
        classe ip: 217.8.112/20
        nome isp:     Amoun for Telecom & Investments
        classe ip: 80.77.160/20
        nome isp:     Applied Science University (ASU)
mi sapete aiutare? (e cmq sto switch non e' che l'abbia capito molto, 
sinceramente)
-- 
Umin
n.p.: Richard Ashcroft - Nature Is The Law [stop]

 mi sapete aiutare?
Attenzione: ti stai inutilmente complicando la vita.
Se i tab sono *sempre* presenti *esattamente* nelle posizioni che hai 
detto (e non altrove), allora si tratta di un file CSV, per cui puoi 
facilmente isolare i vari campi mediante una semplice split, senza alcun 
bisogno di regex.
Una possibile soluzione è la seguente:
use strict;
while ( <SORG> ) {
     chomp;
     my @campi = split /\t/;
     $campi[1] && $campi[2] and print "\tCl. IP: $campi[2]\n" and next;
     $campi[1]              and print "Nom. ISP: $campi[1]\n" and next;
     $campi[0]              and print "\nDomin.: $campi[0]\n"
}
Con i dati di test che hai postato, stampa:
Domin.: ab.qualcosa
Nom. ISP: Ragione Sociale
	Cl. IP: 
12.34.56.78/10
	Cl. IP: 
78.65.43.21/20
Domin.: bc.qualcosa
Nom. ISP: Rag Sociale
	Cl. IP: 12.34.566.78/30
	Cl. IP: 78.65.443.21/50
	Cl. IP: 72.644.43.21/10
(e gestisce correttamente anche l'assenza delle righe degli IP).
Ciao,
Emanuele.

 }
Anzi, ancora più semplice:
use strict;
while ( <SORG> ) {
     chomp;
     my @campi = split /\t/;
     $campi[2] and print "\tClasse IP: $campi[2]\n"  and next;
     $campi[1] and print "\tNome ISP: $campi[1]\n\n" and next;
     $campi[0] and print "\nDominio: $campi[0]\n"
}
Ciao,
Emanuele.

 }
intanto grazie, hai centrato la cosa ed ero commosso al vedere che 
funzionava! :')
pero' il mio problema e' un po' piu' grande, ovvero:
1) il campo[0] deve essere assegnato solo se =~ /^it.\[a-z]+/ (cioe' se 
e' un dominio it.qualcosa, gli altri potrebbero essere anche 
scartati... ma ammetto che non e' un must)
2) il campo[2] puo' avere gli ip anche in versione IPv6, in tal caso 
devo ignorarlo (per questo avevo usato /(\d|\.)+\/\d{2}/)
3) il campo[1] puo' essere nella forma  Nome isp bla bla "(closed)". In 
tal caso il relativo campo[0] e lo stesso campo[1] devono essere 
ignorati
il tutto deve essere inserito in un database sotto forma di
1 record per ogni
dominio1, isp1, classe_ip#1
dominio1, isp1, classe_ip#2
dominio1, isp1, classe_ip#3
dominio2, isp2, classe_ip#1
dominio2, isp2, classe_ip#2
...
etc
per questo cercavo il modo di mettere degli if (o delle regexp)
e tuttavia non ho ancora capito come risolvere, eventualmente, l'insert 
 aggiungendo una nuova classe per ogni coppia dominio/isp che possiede 
piu' di una classe ip
ti chiedo scusa ma mentalmente ragiono ancora un po' secondo altri 
schemi e perl lo sto studiando solo da 2-3 giorni.
-- 
Umin
n. p.: Richard Ashcroft - God In The Numbers

 Emanuele.
misteri della vita:
prima funzionava (infatti l'ho scritto poco fa)
adesso fa i cavoli suoi per quanto il codice ed il file origine sia 
sempre lo stesso
adesso, con quanto scritto sopra, mi da
Dominio: ie.inflow
Dominio:     Inflow
        Classe IP: ALLOCATED PA
        Classe IP: ALLOCATED PA
Dominio: ie.medianet
Dominio:     Solutions By Netsource Limited
        Classe IP: ALLOCATED PA
        Classe IP: ALLOCATED PA
        Classe IP: ALLOCATED PA
        Nome ISP: 2001:1ba8::/32
Dominio: it.abanet
Dominio:     ABANET
        Classe IP: ALLOCATED PA
che non e' assolutamente quello che, correttamente, mi scriveva prima!
percheeee'... :'(
-- 
Umin
n. p.: Stadio - le ultime parole famose

schemi e perl lo sto studiando solo da 2-3 giorni.
Il vantaggio di perl è che spesso non sei obbligato a cambiare i tuoi
schemi: non c'è nessuna necessità di usare costrutti idiomatici di
perl (come gli "and" o lo SWITCH:), se sei abituato in un altro modo o
se non lo trovi conveniente.
Un modo più naturale di trattare i diversi casi, soprattutto se ogni
caso richiede operazioni più complesse di una semplice stampa,
potrebbe essere usare un costrutto if ... elsif ... else....
use strict;
my $dominio, $isp, $classe_ip;
while ( <SORG> ) {
     chomp;
     my @campi = split /\t/;
     if (defined $campi[0]) {
         $dominio = $campi[0];
         ...
     } elsif (defined $campi[2]) {
         ...
     } elsif (defined $campi[1]) {
        $isp = $campi[1];
        ...
     }
}
Oppure fai delle subroutine a cascata (un modo per implementare un
analizzatore a "stati"): letta la prima riga passi alla routine "isp",
che legge una riga e chiama la routine "ip" (o "salta_ip" se l'isp è
chiuso) e così via.
Ciao.

 }
in compenso mi funziona bene e sempre se scrivo semplicemente cosi'
 use strict;
 while ( <SORG> ) {
      chomp;
      my @campi = split /\t/;
print "$campo[0]\t$campo[1]\n";
}
rimane il problema della query e del controllo per i campi con il 
closed e per gli ip classe v6
-- 
Umin
n.p.: Stadio - senza parrucche [stop]

 percheeee'... :'(
Qui l'errore è evidente e, mi spiace dirlo, risiede esclusivamente nelle 
specifiche che hai fornito ;-)
Infatti dai risultati che hai postato si evince chiaramente che la riga 
"Nome ISP" ora principia con una sequenza di 4 spazi (guarda quegli 
spazi che vengono stampati tra la stringa "dominio:" e la stringa 
"Inflow"!) e *non* con un carattere tab, come avevi detto in precedenza.
Se prima lo script funzionava, probabilmente è successo che hai 
involontariamente introdotto degli spazi al posto dei tab nel file di 
input: per evitare la cosa, adopera un editor che evidenzia gli spazi ed 
i tab (e gli altri caratteri normalmente non visibili).
(Sembra che tu abbia passato il file di input attraverso un editor che 
esegue la conversione automatica (tab)->(4 spazi) a inizio riga!)
Se sei così gentile da verificare l'attendibilità delle specifiche 
riguardo i dati di input che hai fornito (soprattutto in ordine alla 
presenza e alla posizione dei tab), e se sei così gentile da postare 
anche dei dati di input sufficientemente estesi (diciamo almeno una 
decina di blocchi, con tutti i casi: lista di IP vuota, ISP closed 
etc.), ti fornirò lo script completo che esegue quello che hai chiesto.
Si tratta di un problema banale, che può essere complicato soltanto 
dall'imprecisione e dall'incompletezza delle specifiche.
Con la tua risposta magari apri un nuovo thread.
Ciao,
Emanuele

ciao a tutti, senza aprire un nuovo post
ho lo stesso problema ma con un particolare in piu' il file che
utilizzo e codificato in utf-8
e vorrei poi fare una query
ho provato semplicemente con un use utf-8
e con < utf-8 nell'open  del file il problema resta nella query che mi
da' errore 
sono letteralmente incasinato con la codifica del file :(


Premesso che non alcuna idea circa i tuoi specifici problemi ("la query 
che mi dà errore" e "sono letteralmente incasinato con la codifica del 
file" sono descrizioni troppo vaghe per le mie modeste capacità 
interpretative e divinatorie), in generale, per leggere file con 
contenuto utf8
open(FH, "<:utf8", "file")
va benissimo.
Per ogni ulteriore dettaglio:
http://perldoc.perl.org/perluniintro.html
http://perldoc.perl.org/perlunicode.html
Tieni presente però che se devi mettere il contenuto del file in un db, 
*anche* il db deve utilizzare la codifica utf8.
In genere i DBMS permettono di specificare la codifica utilizzata in 
fase di creazione del db.
Ciao,
Emanuele.

grazie
scusami della generalita' della spiegazione.
il problema credo sia proprio il settaggio della codifica del DBMS.
infatti stampando a file le query con la corretta codifica le
visualizzo correttamente in utf8.
Potrebbe essere anche un problema di interfacciamento di DBI con il
DBMS?
o una volta settata la codifica dello script e la codifica
input/output, la cosa viene in automatica?
ciao,
maz

 input/output, la cosa viene in automatica?
La cosa viene automatica, come dici tu.
Perl setta automaticamente un flag interno per ogni stringa che proviene 
da una sorgente con codifica utf-8, codifica che verrà poi 
automaticamente onorata ove necessario, ad esempio quando si utilizzano 
funzioni sulle stringhe ( substr(), length() etc. ) o regex.
Comunque sta scritto tutto nei tutorial che ti ho segnalato nel mio 
precedente messaggio.
Poi ci sarebbe anche il modulo Encode, che permette codifiche più generali:
http://search.cpan.org/~dankogai/Encode-2.14/
Infine considera che *tutta* la catena di applicazioni che trattano le 
tue stringhe devono utilizzare la stessa codifica: lo script che prende 
i dati dal file, ma poi anche il DBMS (come ti dicevo l'altra volta), 
poi l'eventuale altro script che riprende i dati dal db, e infine anche 
l'applicazione di visualizzazione dei tuoi report (ad esempio il 
browser, il quale deve essere correttamente informato circa la codifica 
in uso). Basta che una singola applicazione lavori con una codifica 
diversa e, in generale, avrai da qualche parte caratteri /errati/.
Ciao,
Emanuele.