:: Gruppi di Scansione ::
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
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; }
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 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:
Credo sia chiaro.
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.
Nel file ho scritto:
while(fscanf(...) != EOF) {
La fscanf
ritorna
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.