cerca
Gruppi di Scansione
modifica cronologia stampa login logout

Wiki

UniCrema


Materie per semestre

Materie per anno

Materie per laurea


Help

Gruppi di Scansione

 :: Gruppi di Scansione ::

Possa fscanf con tutti i suoi derivati morire nella Geenna! Sciagura su di essi per 7 generazioni!

In questa pagina affronto lo spinoso argomento della fscanf. Perché spinoso? E che ne so, l'aggettivo suonava bene.

Tutto nacque da un problema di Lorenzo: (immaginate la sua voce)
"Yuck! Ho un file di log come il seguente, e devo scansionarlo:":

 log.txt
 www.donnebiotte.it 234
 ftp.ilsitodeipornazzi.com 1982
 www.alfredocimangia.com 9
 www.cheballefscanf.com 9999

Voglio

  1. riconoscere il protocollo, cioè la parte prima del primo punto (www, ftp o quello che ci sarà)
  2. riconoscere il nome
  3. riconoscere l'estensione
  4. riconoscere il numero di visite

Ecco a voi la soluzione, con commenti finali

 gruppo.c
 #include <stdio.h>

 int main() {
	FILE * file;
	char tipo[10];
	char nome[20];
	char estensione[20];
	int valore;

	file = fopen("log.txt", "r");

	while (fscanf(file, "%[^.].%[^.].%[^ ] %d\n",tipo,nome,
                                                     estensione,&valore) !=EOF)   {	

		printf("'s' 'd'\n", tipo,nome,estensione,valore);
                /* etc. etc.*/
	}	

	fclose(file);

	return 0;
 }

Il gruppo di scansione

La riga

 fscanf(file, "%[^.].%[^.].%[^ ] %d\n",tipo,nome,estensione,&valore)

fa tutto il lavoro sporco.

Le parentesi quadre [ ] circondano un cosiddetto gruppo di scansione. Come dice il professore, è un setaccio. Tutto ciò che viene messo tra le quadre, viene letto. Non appena si trova qualche cosa che NON appartiene a ciò che è contenuto tra le quadre, la scansione si ferma.
Quindi, una riga come

 fscanf(file, "%[tetty]", stringa);

leggerà solo le stringhe che contengono una delle lettere contenute nella stringa tetty, come per esempio:

 tetty
 ttteeettttyyttytytttteee
 eeee
 yyyyyy

ma non

 tettamanzi

Non appena arriva alla prima a, la scansione si ferma.

Il gruppo di scansione invertito

Il gruppo di scansione funziona anche con l'accento circonflesso o quel diavolo che è, insomma, il ^, e vuol dire: "tutto ciò che NON è contenuto nelle quadre, va bene. Non appena trovi qualche cosa contenuto nelle parentesi quadre, fermati".

Quindi, la riga

 fscanf(file, "%[^abc]", stringa);

leggerà tutte le stringhe che NON contengono abc, cioè

 defghi
 lmnop
 dddfdssdljfljwer

ma non

 dario

Appena arriva alla a, si ferma, perché è contenuta nel gruppo di scansione.

Nel nostro caso, quindi, la parte

 %[^.].%[^.].%[^ ] %d\n

vuol dire esattamente:

  • Leggi tutto fino a che non trovi un punto, e mettilo nella prima variabile
  • Leggi il punto
  • Leggi quello che resta, fino al prossimo punto, e mettilo nella seconda variabile
  • Leggi il secondo punto
  • Leggi etc. terza variabile
  • Spazio
  • Leggi un intero e salvalo nella variabile
  • Leggi un ritorno a capo (un finelinea)

Credo sia chiaro.

Complichiamoci un poco la vita

Se avessi usato una fscanf così:

 fscanf(file, "%[^.]%*c%[^.]%*c%[^ ] %d\n", tipo,nome,estensione,&valore)

avrebbe funzionato ugualmente.

Il motivo è che ho introdotto una cosa diversa: il %*c. Ciò vuol dire "leggi un carattere e fregatene, e passa al resto", e il resto lo conosciamo già.

Quindi, %*d vuol dire "leggi un intero e fregatene", %*s fregatene della stringa e così via.

I valori di ritorno di fscanf

Nel file ho scritto:

 while(fscanf(...) != EOF) {

La fscanf ritorna

  • il numero di variabili correttamente lette
  • oppure EOF se ha finito il file

Nel nostro caso, quindi, avrei anche potuto scrivere

 while(fscanf(...) == 4) {

cioè, esegui il ciclo fintantoché fscanf legge correttamente 4 variabili per volta. E infatti avevo 4 variabili (andate sopra a vedere, se non ci credete).

Se avessimo trovato una riga, nel file log.txt, del tipo

 ...
 www.negroni.it
 ...

senza un numero dopo, fscanf avrebbe ritornato un 3, e il while avrebbe rilevato 3 != 4 e avrebbe terminato il ciclo.


Torna al Laboratorio di C | Programmazione