Newsgroup: it.comp.lang.perl
Titolo: Estrarre coppie di valori da file ASCII

Buongiorno,
	  Sono un po' un principiante di perl, ed ho un problema che non
	  sono riuscito a risolvere negli ultimi 2 giorni.
	  La situazione e' questa: ho un file con del testo. Al suo
	  interno ci sono coppie di valori delimitati da pipe nel seguente
	  formato:
	  	||CHIAVE||||VALORE||
	  Possono esistere piu' coppie di valori su ogni riga. Sto
	  cercando di estrarre queste coppie di valori ed inserirle in un
	  array bidimensionale. Qualcuno ha una soluzione rapida ed
	  indolore? :) Il problema principale che sto avendo sta nello
	  scrivere l'espressione regolare che mi permetta di estrarre
	  CHIAVE e VALORE.
	  Ringrazio anticipatamente per qualunque tipo di aiuto. Buona
	  giornata a tutti!
--
Kristian

	  Possono esistere piu' coppie di valori su ogni riga.
Come sono separate le coppie? Fai un esempio di più coppie su una stessa
riga.
Ciao.

riga.
Per esempio, questo funziona, se le coppie sono semplicemente accostate,
come dopo l'__END__:
    while (<DATA>) {
        while (/\|\|([^|]+)\|\|\|\|([^|]+)\|\|/cg) {
            print $1, "=", $2, "\n";
        }
        print "\n";
    }
    __END__
    ||CHIAVE1||||VALORE1||||CHIAVE2||||VALORE2||||CHIAVE3||||VALORE3||
    ||1CHIAVE1||||1VALORE1||
E' possibile, in vari modi, evitare di quotare tutti i caratteri pipe; per
esempio, questa è una scrittura equivalente (e appena un po' più leggibile)
dell'espressione regolare sopra:
    /\Q||\E([^|]+)\Q||||\E([^|]+)\Q||\E/cg
Ciao.

, 
	  Giovanni Zezza ha scritto:

	Ciao.. ecco qua l'esempio di un file:
stampa.txt
-------------------------------------------------
un po' di parole di testo.. altro testo
un po' di parole di testo... testo testo testo
altro testo qui ||CHIAVE1||||VALORE1|| altro testo
altro testo ||CHIAVE2||||VALORE2|| altro testo ||CHIAVE3||||VALORE3||
||CHIAVE4||||VALORE4|| altro||CHIAVE5||||VALORE5||altro ||CHIAVE6||||VALORE6||
altro testo qui ||CHIAVE7||||VALORE17| altro testo
-------------------------------------------------
--
Kristian

, 
	  Giovanni Zezza ha scritto:

	Ciao Giovanni,
	Grazie per questi "hints" ! ;)
	Comincio gia' a vedere se riesco ad arrivare a qualcosa con i tuoi
	aiuti. Non sono molto esperto di espressioni regolari, e non ho
	ancora trovato una guida che insegni come usarle. Conosci qualche
	risorsa online?
	Tante cose,
--
Kristian

	Ciao.. ecco qua l'esempio di un file:
L'esempio che ho scritto è migliore di quello che pensavo: va bene anche
nei casi che hai esemplificato. L'unica che non funziona è questa riga:
  >altro testo qui ||CHIAVE7||||VALORE17| altro testo
perché manca un pipe. Spero sia stato un errore.
L'importante è che le coppie siano tutte conformate come hai detto, e che
non ci siano altri caratteri pipe nelle altre zone del testo.
Ciao.

	risorsa online?
Comincia da perlretut e perlre di perl. Altre risorse senz'altro ci sono,
ma al momento non le ho presenti.
Ciao.

>     /\Q||\E([^|]+)\Q||||\E([^|]+)\Q||\E/cg
	Wow!!! Ha funzionato!
	Ho preso pari pari il tuo blocco che hai scritto sopra e ho fatto:
	while ( <INFILE> )
	{
		while (/\|\|([^|]+)\|\|\|\|([^|]+)\|\|/cg) {
            	print $1, "=", $2, "\n";
      	}
	}
	Questo ha estratto tutto quello che mi serviva dal file. Mi e'
	comunque tutt'ora un po' oscuro il funzionamento. Prima di tutto
	non capisco come il secondo while() prenda l'input dal file... chi
	glielo dice?! Poi, l'espressione che hai scritto 
 
		/\|\|([^|]+)\|\|\|\|([^|]+)\|\|/cg
	io la tradurrei come
 
		match-a tutte le istanze (la "g".. e la "c" a che serve?)
		del pattern specificato (cioe' ||testo||||testo||) 
		riga per riga. 
 
	Sbaglio a pensare che while() processi riga per riga? Ma se e'
	cosi', come fa la print() successiva a riuscire a stampare due
	coppie CHIAVE-VALORE che stanno sulla stessa riga?! Non capisco.
	Poi... che vuol dire esattamente [^|]+ ? L'accento circonflesso
	non serve ad indicare "inizio"? E cosa c'entrano il pipe e il +?
	Non importa che mi delucidi i dubbi se non ne hai voglia o tempo. 
	Comunque grazie... senza di te non ce l'avrei mai fatta! ;) 
 
--
Kristian

 perché manca un pipe. Spero sia stato un errore.
	Si si... erroraccio mio! Scusa... ;)
--
Kristian

 ma al momento non le ho presenti.
 
http://japhy.perlmonk.org/book/
ciao
Stefano
+++
In generale i link che segnalo qui sono raccolti in questa pagina:
 
http://larsen.perlmonk.org/links/perl.html

	Non importa che mi delucidi i dubbi se non ne hai voglia o tempo. 
Il mio datore di lavoro è molto liberale, ma chiacchierare sotto i suoi
occhi nei newsgroup invece di lavorare è forse mettere un po' troppo alla
prova la sua liberalità. Magari stasera.
Ciao.

	non serve ad indicare "inizio"? E cosa c'entrano il pipe e il +?
L'accento circonflesso indica "inizio" se al di fuori una classe (quello che
sta dentro le parentesi quadre); all'interno (e all'inizio) di una classe ha
valore di negazione. Quindi, dato che una classe sta per "qualsiasi
carattere fra questi", con l'accento circonflesso diventa "qualsiasi
carattere NON fra questi". In prati sto cercando un carattere che NON sia
una pipe. Il + è un quantificatore, e vuol dire "una o più occorrenze di
quello che precede".
Però, scusa, mentre il modificatore /c è pura "magia nera" Perl, queste
ultime sono proprio le basi delle espressioni regolari. Sui fondamentali non
si possono fare sconti, bisogna studiarseli per forza.
Ciao.

 si possono fare sconti, bisogna studiarseli per forza.
	Sono semplicemente rimasto senza parole.
	Giovanni... con le tue spiegazioni mi hai aperto un mondo..
	davvero!
	Hai pienamente ragione sul fatto di dover sapere almeno i
	fondamenti delle espressioni regolari, e come ha puntualizzato
	Karl in precendenza, e' giusto che cerchi di risolvere i
	problemi da solo prima, e di postare il risultato dei miei
	tentativi solo in casi disperati per consultare/chiedere aiuto 
	a dei Guru di Perl come te.
	Ho gia' cominciato a leggere perlretut... cerchero' di non 
	abusare piu' dell'esperienza altrui come ho fatto quest'oggi, e 
	mi scuso nuovamente per l'ingresso cosi' misero nel newsgroup.
	Essendo un principiante di perl e alle prese con un problema da 
	risolvere nel minor tempo possibile, ho cercato disperatamente 
	aiuto per muovere i primi passi.
	Spero di poter pure io dare un contributo attivo al gruppo al
	piu' presto, anche se con l'esperienza che si respira da queste
	parti, la vedo molto dura!!! ;)
-- 
Kristian

     }
	Hmmm... ci stavo pensando poco fa.
	Stando alla tua spiegazione nell'altro post, mi sembra di capire
	che se "c" non ci fosse, il secondo ciclo while() ripartirebbe
	dall'inizio della riga per trovare le istanze che match-ano
	l'espressione. Quindi su una riga dove sono presenti piu' coppie
	di valori, non verrebbe a crearsi una situazione di ciclo infinito
	dove e' sempre la prima istanza a match-are? Forse ho capito male,
	ma hai detto che "/c" serve per tenere il cursore fermo alla
	posizione e non ricominciare da inizio riga, o sbaglio? 
	Comunque sia, ho provato a togliere la "/c" e non e' cambiato
	nulla: funziona come prima.
	perlretut dice: 
	... " If you don't want the position reset after failure to match,
	add the "//c" " ...
	Se su una riga non esiste l'espressione che sto cercando, e quindi
	l'espressione non match-a, perche' mai NON dovrei volere un
	"position reset" (che io interpreto come "cercare sulla prossima
      riga da inizio riga")?
	Colgo l'occasione per augurare a tutti buon lavoro!
--
Kristian

      riga da inizio riga")?
Infatti basta il /g (a dimostrazione che anch'io non ho capito tutto quello
che credo di aver capito). La condizione di ciclo infinito però non può
verificarsi, perché ad un certo punto il match fallisce e si esce dal
ciclo. Insomma, /c è inutile, ma non dannoso.
Per capire quello che succede, puoi provare le due versioni:
con il modificatore /c
    while (<DATA>) {
        while (/\Q||\E([^|]+)\Q||||\E([^|]+)\Q||\E/cg) {
            print $1, "=", $2, " ", pos, "\n";
        }
        print pos, "\n";
    }
senza modificatore /c
    while (<DATA>) {
        while (/\Q||\E([^|]+)\Q||||\E([^|]+)\Q||\E/g) {
            print $1, "=", $2, " ", pos, "\n";
        }
        print pos, "\n";
    }
Dal ciclo si esce sempre, ma nel primo caso hai a disposizione l'ultimo
valore di pos, con cui fare delle cose (per esempio, in combinazione con
l'asserzione \G), nel secondo si ricomincia da capo. Con un'opportuna
combinazione di \G e /c si può, immagino, realizzare effettivamente una
condizione di ciclo infinito, ma in questo momento non sono in grado di
costruire un esempio.
Ciao.